Add initial argument parsing capabilites to CC_Functions.CommandLine

This commit is contained in:
JFronny 2020-09-11 11:41:08 +02:00
parent 7c9a5aa73d
commit 1e451b78f9
3 changed files with 127 additions and 1 deletions

View File

@ -3,13 +3,30 @@ using System.Drawing;
using System.Threading;
using CC_Functions.Commandline;
using CC_Functions.Commandline.TUI;
using CC_Functions.Core;
namespace CLITest
{
internal class Program
{
private static void Main(string[] args)
private static void Main()
{
Thread.CurrentThread.ForceInvariantCulture();
//Parse test
if (new ArgsParse(new[] { "--meme", "Fuk u", "--meme:yeet", "--meme:yote", "--meme" })["meme"] != "yote")
throw new Exception("ArgsParse error 1");
if (!new ArgsParse(new[] { "--meme", "Fuk u", "--meme:yeet", "--meme:yote", "--meme" }).GetBool("meme"))
throw new Exception("ArgsParse error 2");
if (new ArgsParse(new[] {"--meme:"}).GetBool("meme"))
throw new Exception("ArgsParse error 3");
if (!new ArgsParse(new[] {"--meme:true"}).GetBool("mEme"))
throw new Exception("ArgsParse error 4");
if (new ArgsParse(new[] {"--meme:1.1.2019"}).Get<DateTime>("meme") != new DateTime(2019, 1, 1))
throw new Exception("ArgsParse error 5");
if (new ArgsParse(new[] {"--meme:2019"}).Get("meme", s => s == null ? DateTime.Now : DateTime.Parse("1.1." + s)) != new DateTime(2019, 1, 1))
throw new Exception("ArgsParse error 6");
//Display test
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.White;
Console.Clear();

98
Commandline/ArgsParse.cs Normal file
View File

@ -0,0 +1,98 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace CC_Functions.Commandline
{
/// <summary>
/// A class to provide basic parsing for program arguments
/// </summary>
public class ArgsParse : IEnumerable<string>
{
private readonly string[] _args;
/// <summary>
/// Create a new instance based on the specified args
/// </summary>
/// <param name="args">The inputted args. Should be a parameter of the main method</param>
public ArgsParse(string[] args) => _args = args ?? throw new NullReferenceException();
/// <summary>
/// Shadowed from the base args
/// </summary>
/// <param name="i">The index in the base args</param>
public string this[int i]
{
get => _args[i];
set => _args[i] = value;
}
/// <summary>
/// Shadowed from the base args
/// </summary>
/// <returns>An enumerator for the base args</returns>
IEnumerator<string> IEnumerable<string>.GetEnumerator() => ((IEnumerable<string>)_args).GetEnumerator();
/// <summary>
/// Shadowed from the base args
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator() => _args.GetEnumerator();
/// <summary>
/// Gets the string specified for this key or null
/// </summary>
/// <param name="i">The name of the parameter</param>
public string? this[string i]
{
get
{
string? selected = null;
foreach (string s in _args)
if (s.TrimStart('-', '/').ToLower().StartsWith($"{i.ToLower()}:"))
selected = string.Join("", s.TrimStart('-', '/').Skip(i.Length + 1));
return selected;
}
}
/// <summary>
/// Gets the string specified for this key or null
/// </summary>
/// <param name="i">The name of the parameter</param>
/// <returns>The value or null</returns>
public string? GetString(string i) => this[i];
/// <summary>
/// Gets a boolean value with the specified name. Either specified as --i or --i:true
/// </summary>
/// <param name="i">The name of the parameter</param>
/// <returns>The value</returns>
public bool GetBool(string i) => _args.Any(s => s.ToLower().TrimStart('-', '/') == i.ToLower()) || bool.TryParse(this[i], out bool res) && res;
/// <summary>
/// Gets an arg using a transformer specified by you. The value passed will be the same as this[i]
/// </summary>
/// <param name="i">The name of the parameter</param>
/// <param name="func">A null-safe function to convert a string to the expected type</param>
/// <typeparam name="T">The type to convert to</typeparam>
/// <returns>The converted value</returns>
public T Get<T>(string i, Func<string?, T> func) => func(this[i]);
/// <summary>
/// Uses reflection to call the Parse method on types providing it. Use Get() with a func param for other types
/// This will return null if the type is not found
/// </summary>
/// <param name="i">The name of the parameter</param>
/// <typeparam name="T">The type to convert to</typeparam>
/// <returns>The converted value</returns>
public T Get<T>(string i)
{
MethodInfo[] parse = typeof(T).GetMethods().Where(s => s.Name.ToLower() == "parse"
&& s.GetParameters().Length == 1
&& s.GetParameters()[0].ParameterType == typeof(string)
&& s.ReturnType == typeof(T)
&& !s.IsAbstract && !s.IsPrivate && s.IsStatic).ToArray();
if (parse.Length == 0)
throw new InvalidOperationException("Could not find a valid parse method");
string? v = this[i];
if (v == null)
return default;
return (T) parse[0].Invoke(null, new object[] {v});
}
}
}

View File

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Threading;
namespace CC_Functions.Core
{
@ -240,5 +242,14 @@ namespace CC_Functions.Core
ignoredPaths);
return result;
}
/// <summary>
/// Sets the threads cultureInfo properties to InvariantCulture. For testing
/// </summary>
/// <param name="thread">The thread to modify</param>
public static void ForceInvariantCulture(this Thread thread)
{
thread.CurrentCulture = CultureInfo.InvariantCulture;
thread.CurrentUICulture = CultureInfo.InvariantCulture;
}
}
}