Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to convert Arguments object back into args string #114

Open
issacg opened this issue Dec 18, 2013 · 5 comments
Open

Option to convert Arguments object back into args string #114

issacg opened this issue Dec 18, 2013 · 5 comments

Comments

@issacg
Copy link

issacg commented Dec 18, 2013

Hi

In my use-case, I needed to (occasionally) construct command line parameters for another instance of my process, and overloaded my class' ToString method to do so. I'd love to contribute the code back, but not sure if it's something that's needed, or where the best place in the library would be to put it.

I've included the code here, and if there is interest, and someone would give me some basic guidance as to where the correct place to add this to the library would be, I'd be happy to make a pull request (time permitting ;))

class MyArguments {
        // Add some option-properties

        public override string ToString()
        {
            string res = "";
            // Get a list of all properties with OptionAttribute
            var props = this.GetType().GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(OptionAttribute)));
            // Now search the list to extract the attribute data
            foreach (PropertyInfo prop in props)
            {
                object[] attrs = prop.GetCustomAttributes(true);
                foreach (object attr in attrs)
                {
                    OptionAttribute oa = attr as OptionAttribute;
                    if (oa != null)
                    {
                        // We found an OptionAttribute!
                        Type t = prop.GetType();
                        var data = prop.GetValue(this, null);
                        // Check if value is "default(t)" or not
                        if (data != (t.IsValueType ? Activator.CreateInstance(t) : null))
                        {
                            // Only print out non-empty parameters
                            res += "--" + oa.LongName + " " + data.ToString() + " ";
                        }
                    }
                }
            }
            return res;
        }
}
@allonhadaya
Copy link

Nice! Not sure about how this all fits into the library, but I played around with your code and came up with this. It uses some more linq and extracts the functionality into an abstract base class.

using System;
using System.Linq;
using CommandLine;

/// <summary>
/// A base class for options that can be turned back into an argument string.
/// </summary>
public abstract class ReversableOptions
{
    public override string ToString()
    {
        return string.Concat(this
            .GetType()
            .GetProperties()
            .Where(p => Attribute.IsDefined(p, typeof(OptionAttribute)))
            // for all properties with option attributes
            .SelectMany(p => p
                .GetCustomAttributes(typeof(OptionAttribute), inherit: true)
                .Select(a => (OptionAttribute)a)
                // get the type, name, and data
                .Select(a => new {
                    type = p.GetType(),
                    name = a.LongName,
                    data = p.GetValue(this, null)
                })
                // where data is not default
                .Where(v => v.data != ((v.type.IsValueType) ? Activator.CreateInstance(v.type) : null))
                // make an argument string
                .Select(v => string.Format("--{0} {1} ", v.name, v.data))));
    }
}

I was kicking around the idea of making a tag interface with a single Reverse extension, but every implementer would have to do something like this:

class MyOptions : ISomeTag
{
    public override string ToString()
    {
        return this.Reverse();
    }
}

which seems a bit crufty.

Anyways, hope this helps.

@issacg
Copy link
Author

issacg commented Dec 18, 2013

Yeah, the Reverse tag would be a bit sucky. I don't really have a better idea, though. Maybe just leave the ToString code as a Gist and mention it in the docs...

I tried using your ToString as a drop-in replacement to mine, and it actually did not seem to work - I'll try to find some time tomorrow to look into it

@allonhadaya
Copy link

Yeah, I think I just found the bug... A small typo.

@allonhadaya
Copy link

Sorry about that, just updated my earlier comment with the fix. I think a gist would be a good place to start.

@issacg
Copy link
Author

issacg commented Dec 18, 2013

It works now.

https://gist.github.com/issacg/8024973

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants