Skip to content

How about support for verbs/commands? #17

Closed
@alexanderfast

Description

@alexanderfast

Hi.

I like this library a lot! But one thing I'm missing is support for "verbs". Like when the first argument on command line is a verb which then has options specific to that verb. Similar to git commit -m "message".

I put the code below together as a proof of concept. Though, looking at it now I think I would have preferred to have the Option attribute assigned to parameters of the method instead of a dedicated class, but that would require some more intrusive changes. Is this something you would be interested in exploring or is totally out of scope for this library?

using System;
using System.Linq;
using System.Reflection;

using CommandLine;

namespace SampleApp
{
    public class VerbProgram
    {
        private static void Main(string[] args)
        {
            //MyVerbs.FooOptions options = new MyVerbs.FooOptions();
            //if (!CommandLineParser.Default.ParseArguments(
            //    new[] { "--flag" }, options))
            //{
            //    Environment.Exit(1);
            //}

            MyVerbs verbs = new MyVerbs();
            if (!VerbParser.Default.ParseArguments(
                new[] { "foo", "--flag" }, verbs))
            {
                Environment.Exit(1);
            }

            Environment.Exit(0);
        }
    }

    internal class MyVerbs
    {
        internal class FooOptions : CommandLineOptionsBase
        {
            [Option("f", "flag", Required = true)]
            public bool Flag { get; set; }
        }

        [Verb]
        public void Foo(FooOptions options)
        {
            Console.WriteLine(options.Flag);
        }
    }

    public class VerbAttribute : Attribute
    {
        /// <summary>
        /// By default the name of the verb is a lowercase version of the
        /// method name, set this property to override.
        /// </summary>
        public string Name { get; set; }

        public string HelpText { get; set; }
    }

    internal class VerbParser
    {
        public static VerbParser Default = new VerbParser();
        internal ICommandLineParser ArgumentParser = CommandLineParser.Default;

        public bool ParseArguments(string[] args, object verbs)
        {
            // store name of verb and remove it from args
            var verbName = args[0];
            args = args.Skip(1).ToArray();

            // find verb method
            Pair<MethodInfo, VerbAttribute> verb = null;
            foreach (Pair<MethodInfo, VerbAttribute> pair in
                ReflectionUtil.RetrieveMethods<VerbAttribute>(verbs))
            {
                string name = pair.Right.Name;
                if (string.IsNullOrEmpty(name))
                {
                    name = pair.Left.Name.ToLower();
                }
                if (verbName.Equals(name))
                {
                    verb = pair;
                    break;
                }
            }
            if (verb == null)
            {
                return false; // verb not found
            }

            object options = Activator.CreateInstance(
                verb.Left.GetParameters()[0].ParameterType);
            if (!ArgumentParser.ParseArguments(args, options))
            {
                return false; // couldnt parse verb arguments
            }

            verb.Left.Invoke(verbs, new[] {options});
            return true;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions