From b0a9a2047c9ae333ac4bdcd9576743386ec75456 Mon Sep 17 00:00:00 2001 From: AndreasSasDev Date: Sun, 28 Apr 2024 15:32:16 +0200 Subject: [PATCH] Feat: Working Async methods & params --- .../ArgsTest.cs | 6 ++--- .../HelloAtlas.cs | 9 +++++-- .../Program.cs | 5 +++- .../IParameterParser.cs | 3 ++- .../IParameters.cs} | 6 ++--- src/CliArgsParser/CommandMethodInfo.cs | 6 ++--- src/CliArgsParser/ParameterParser.cs | 12 ++++------ src/CliArgsParser/PreMade/Args/ForceArgs.cs | 4 ++-- src/CliArgsParser/PreMade/Args/NoArgs.cs | 6 ++--- .../PreMade/Parsers/AbstractParser.cs | 8 +++---- .../PreMade/Parsers/ArgsParser.cs | 24 +++++++++++++------ 11 files changed, 52 insertions(+), 37 deletions(-) rename src/{CliArgsParser/Attributes/ParametersAttribute.cs => CliArgsParser.Contracts/IParameters.cs} (80%) diff --git a/examples/CliArgsParser.Examples.RegisterAtlas/ArgsTest.cs b/examples/CliArgsParser.Examples.RegisterAtlas/ArgsTest.cs index 17d6c88..8e2230f 100644 --- a/examples/CliArgsParser.Examples.RegisterAtlas/ArgsTest.cs +++ b/examples/CliArgsParser.Examples.RegisterAtlas/ArgsTest.cs @@ -3,13 +3,13 @@ // --------------------------------------------------------------------------------------------------------------------- using CliArgsParser.Attributes; +using CliArgsParser.Contracts; namespace CliArgsParser.Examples.RegisterAtlas; // --------------------------------------------------------------------------------------------------------------------- // Code // --------------------------------------------------------------------------------------------------------------------- -[Parameters] -public class ArgsTest { - [AutoArgFlag("username")] public string Username { get; set; } = "undefined"; +public class ArgsTest : IParameters { + [AutoArgValue("username")]public string Username { get; set; } = "undefined"; } \ No newline at end of file diff --git a/examples/CliArgsParser.Examples.RegisterAtlas/HelloAtlas.cs b/examples/CliArgsParser.Examples.RegisterAtlas/HelloAtlas.cs index 78b8107..2fa04ab 100644 --- a/examples/CliArgsParser.Examples.RegisterAtlas/HelloAtlas.cs +++ b/examples/CliArgsParser.Examples.RegisterAtlas/HelloAtlas.cs @@ -24,8 +24,13 @@ public async Task CommmandHelloAsync() { } [Command("hello-test")] - public void CommmandHelloAsyncArgsTest(ArgsTest argsTest) { - // await Task.Delay(100); + public void CommmandTestArgs(ArgsTest argsTest) { + Console.WriteLine($"IT WORKS! & with args : {argsTest.Username}"); + } + + [Command("hello-test-async")] + public async Task CommmandTestArgsAsync(ArgsTest argsTest) { + await Task.Delay(100); Console.WriteLine($"IT WORKS! in ASYNC & with args : {argsTest.Username}"); } } \ No newline at end of file diff --git a/examples/CliArgsParser.Examples.RegisterAtlas/Program.cs b/examples/CliArgsParser.Examples.RegisterAtlas/Program.cs index bbee8de..02f67be 100644 --- a/examples/CliArgsParser.Examples.RegisterAtlas/Program.cs +++ b/examples/CliArgsParser.Examples.RegisterAtlas/Program.cs @@ -11,7 +11,10 @@ namespace CliArgsParser.Examples.RegisterAtlas; // --------------------------------------------------------------------------------------------------------------------- static class Program { public static async Task MainAsync(IParser parser, string[] args) { - await parser.TryParseAsync("hello && hello-async && hello-test --username=andreas"); + // await parser.TryParseAsync("hello"); + // await parser.TryParseAsync("hello-async "); + // await parser.TryParseAsync("""hello-test --username="andreas" """); + await parser.TryParseAsync("hello-test-async --username=andreas"); } public static void Main(string[] args) { diff --git a/src/CliArgsParser.Contracts/IParameterParser.cs b/src/CliArgsParser.Contracts/IParameterParser.cs index cd8635c..aff3e6d 100644 --- a/src/CliArgsParser.Contracts/IParameterParser.cs +++ b/src/CliArgsParser.Contracts/IParameterParser.cs @@ -8,5 +8,6 @@ namespace CliArgsParser.Contracts; // Code // --------------------------------------------------------------------------------------------------------------------- public interface IParameterParser { - public object? Parse(Dictionary? args); + public Type ParamsType { get; } + public IParameters? Parse(Dictionary? args); } \ No newline at end of file diff --git a/src/CliArgsParser/Attributes/ParametersAttribute.cs b/src/CliArgsParser.Contracts/IParameters.cs similarity index 80% rename from src/CliArgsParser/Attributes/ParametersAttribute.cs rename to src/CliArgsParser.Contracts/IParameters.cs index 8bb05ab..13f2d7d 100644 --- a/src/CliArgsParser/Attributes/ParametersAttribute.cs +++ b/src/CliArgsParser.Contracts/IParameters.cs @@ -2,12 +2,12 @@ // Imports // --------------------------------------------------------------------------------------------------------------------- -namespace CliArgsParser.Attributes; +namespace CliArgsParser.Contracts; // --------------------------------------------------------------------------------------------------------------------- // Code // --------------------------------------------------------------------------------------------------------------------- -[AttributeUsage(AttributeTargets.Class)] -public class ParametersAttribute : Attribute { + +public interface IParameters { } \ No newline at end of file diff --git a/src/CliArgsParser/CommandMethodInfo.cs b/src/CliArgsParser/CommandMethodInfo.cs index 64dc926..0378a7e 100644 --- a/src/CliArgsParser/CommandMethodInfo.cs +++ b/src/CliArgsParser/CommandMethodInfo.cs @@ -40,7 +40,7 @@ public static Delegate GetDelegate(MethodInfo info, object atlas, ILogger logger try { switch (info.GetParameters().Length) { // Method is async and has parameters - case > 1 when isAsync && parameterType != typeof(NoArgs): { + case >= 1 when isAsync && parameterType != typeof(NoArgs): { Type delegateType = typeof(Func<,>).MakeGenericType(parameterType, typeof(Task)); commandDelegate = Delegate.CreateDelegate(delegateType, atlas, info); logger.Debug("Created a delegate of type: {delegateType}", delegateType.Name); @@ -48,7 +48,7 @@ public static Delegate GetDelegate(MethodInfo info, object atlas, ILogger logger } // If method is non-async action and has parameters - case > 1 when !isAsync && parameterType != typeof(NoArgs): { + case >= 1 when !isAsync && parameterType != typeof(NoArgs): { Type delegateType = typeof(Action<>).MakeGenericType(parameterType); commandDelegate = Delegate.CreateDelegate(delegateType, atlas, info); logger.Debug("Created a delegate of type: {delegateType}", delegateType.Name); @@ -78,7 +78,7 @@ public static Delegate GetDelegate(MethodInfo info, object atlas, ILogger logger return commandDelegate; } - + private static IParameterParser CreateParameterParser(MethodInfo info) { return new ParameterParser(GetCommandAttribute(info)?.ArgsType ?? typeof(NoArgs)); } diff --git a/src/CliArgsParser/ParameterParser.cs b/src/CliArgsParser/ParameterParser.cs index 98b0618..c26d7a6 100644 --- a/src/CliArgsParser/ParameterParser.cs +++ b/src/CliArgsParser/ParameterParser.cs @@ -3,7 +3,6 @@ // Imports // --------------------------------------------------------------------------------------------------------------------- using System.Reflection; -using CliArgsParser.Attributes; using CliArgsParser.Contracts; using CliArgsParser.Contracts.Attributes; @@ -16,13 +15,13 @@ public class ParameterParser : IParameterParser { private readonly Dictionary _valueProperties = new(); private readonly Dictionary _flagProperties = new(); - private Type _type; + public Type ParamsType { get; private set; } // ----------------------------------------------------------------------------------------------------------------- // Methods // ----------------------------------------------------------------------------------------------------------------- public ParameterParser(Type type) { - _type = type; + ParamsType = type; PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance ); foreach (PropertyInfo? prop in propertyInfos) { @@ -44,10 +43,9 @@ public ParameterParser(Type type) { /// /// The command-line arguments. /// An instance of the specified parameter options type. - public object? Parse(Dictionary? args) { - object? result = Activator.CreateInstance(_type); - - if (args == null) { + public IParameters? Parse(Dictionary? args) { + IParameters? result = (IParameters?)Activator.CreateInstance(ParamsType); + if (result == null) { return result; } diff --git a/src/CliArgsParser/PreMade/Args/ForceArgs.cs b/src/CliArgsParser/PreMade/Args/ForceArgs.cs index 2fe1d73..82dac44 100644 --- a/src/CliArgsParser/PreMade/Args/ForceArgs.cs +++ b/src/CliArgsParser/PreMade/Args/ForceArgs.cs @@ -3,13 +3,13 @@ // --------------------------------------------------------------------------------------------------------------------- using CliArgsParser.Attributes; +using CliArgsParser.Contracts; namespace CliArgsParser.PreMade.Args; // --------------------------------------------------------------------------------------------------------------------- // Code // --------------------------------------------------------------------------------------------------------------------- -[Parameters] -public class ForceArgs { +public class ForceArgs : IParameters { [ArgFlag("force", "Forces stuff")] public bool IsForced { get; set; } = false; } \ No newline at end of file diff --git a/src/CliArgsParser/PreMade/Args/NoArgs.cs b/src/CliArgsParser/PreMade/Args/NoArgs.cs index 1e506c4..267bade 100644 --- a/src/CliArgsParser/PreMade/Args/NoArgs.cs +++ b/src/CliArgsParser/PreMade/Args/NoArgs.cs @@ -1,15 +1,13 @@ // --------------------------------------------------------------------------------------------------------------------- // Imports // --------------------------------------------------------------------------------------------------------------------- - -using CliArgsParser.Attributes; +using CliArgsParser.Contracts; namespace CliArgsParser.PreMade.Args; // --------------------------------------------------------------------------------------------------------------------- // Code // --------------------------------------------------------------------------------------------------------------------- -[Parameters] -public class NoArgs { +public class NoArgs : IParameters{ } \ No newline at end of file diff --git a/src/CliArgsParser/PreMade/Parsers/AbstractParser.cs b/src/CliArgsParser/PreMade/Parsers/AbstractParser.cs index 49c252e..62832be 100644 --- a/src/CliArgsParser/PreMade/Parsers/AbstractParser.cs +++ b/src/CliArgsParser/PreMade/Parsers/AbstractParser.cs @@ -38,9 +38,9 @@ public Dictionary GetArgs(string argsInput) { .Matches(argsInput) .Where(match => match.Success) .ToDictionary( - match => match.Groups[1].Value, - match => match.Groups[2].Success - ? match.Groups[2].Value.Trim('"') + match => match.Groups[2].Value, + match => match.Groups[3].Success + ? match.Groups[3].Value.Trim('"') : "True" ); } @@ -69,7 +69,7 @@ public IEnumerable GetCommands(string input) { .Select(s => s.Trim()); } - [GeneratedRegex("""(--|-)(\w+)(=\"[^\"]*\"|\w*)?""")] + [GeneratedRegex("""(--|-)(\w+)(?:=(\"[^\"]*\"|\w*))?""")] public static partial Regex ArgsRegex(); [GeneratedRegex("""&&(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)""")] diff --git a/src/CliArgsParser/PreMade/Parsers/ArgsParser.cs b/src/CliArgsParser/PreMade/Parsers/ArgsParser.cs index d6306cd..bfe610d 100644 --- a/src/CliArgsParser/PreMade/Parsers/ArgsParser.cs +++ b/src/CliArgsParser/PreMade/Parsers/ArgsParser.cs @@ -2,6 +2,7 @@ // Imports // --------------------------------------------------------------------------------------------------------------------- +using CliArgsParser.Contracts; using CliArgsParser.Contracts.Common; using CliArgsParser.PreMade.Args; @@ -24,7 +25,8 @@ public class ArgsParser : AbstractParser { } try { - object? parameters = commandRecord.ParameterParser.Parse(args); + var parameters = commandRecord.ParameterParser.Parse(args); + if(parameters?.GetType() == typeof(NoArgs)) { output = (T)commandRecord.Delegate.DynamicInvoke()!; return true; @@ -66,11 +68,16 @@ public override async Task TryParseAsync(string input) { } try { - Log.Debug($"Parsing parameters for command: {commandName}"); - object? parameters = commandRecord?.ParameterParser.Parse(args); + + Log.Debug("Parsing parameters for command: {name}",commandName); + + IParameters? parameters = commandRecord.ParameterParser.Parse(args); + + Log.Debug("Found params : {@params}", parameters); + if (parameters?.GetType() == typeof(NoArgs)) { Log.Debug($"Command: {commandName} has no parameters."); - if (commandRecord?.Delegate is Func func) { + if (commandRecord.Delegate is Func func) { Log.Debug("Invoking async delegate without parameters."); await func(); // For Async methods without parameters continue; @@ -81,14 +88,17 @@ public override async Task TryParseAsync(string input) { continue; } } - if (commandRecord.Delegate is Func funcWithParam) { + + Log.Debug("{@a}", commandRecord?.Delegate?.Method); + if (commandRecord is { IsAsync: true }) { Log.Debug("Invoking async delegate with parameters."); - await funcWithParam(parameters); // For Async methods with parameters + var task = (Task)commandRecord.Delegate?.DynamicInvoke(parameters)!; + await task; continue; } Log.Debug("Invoking synchronous delegate with parameters."); - commandRecord.Delegate.DynamicInvoke(parameters); // For non-async methods with parameters + commandRecord?.Delegate?.DynamicInvoke(parameters); // For non-async methods with parameters } catch (Exception e) { Log.Error(e, "Error occurred during command execution.");