Skip to content

Support for Uri #210

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

Closed
mac2000 opened this issue Jul 28, 2015 · 9 comments
Closed

Support for Uri #210

mac2000 opened this issue Jul 28, 2015 · 9 comments
Assignees

Comments

@mac2000
Copy link

mac2000 commented Jul 28, 2015

Here is what I trying to do:

class Options {
    [Option('e', "Endpoint", HelpText = "[uri] Endpoint, e.g.: http://localhost:9200")]
    public Uri Endpoint { get; set; }
}

class Program {
    static void Main(string[] args) {
        Parser.Default.ParseArguments<Options>(args).WithParsed(Run);
    }

    static void Run(Options options) {
        Console.WriteLine("Endpoint: {0}", options.Endpoint);
    }
}

but unfortunately no matter how I call executable there is always error saying that Option 'Endpoint, e' is defined with a bad format.

@gsscoder
Copy link
Owner

@mac2000, unfortunately there's actually not a way to make this working without extra coding (using a string and creating the instance in another property get).

I've proposed something that can help in a reply in this issue: #158.

Thanks for reporting this need. For the moment try to bypass the problem using a string, but you can be sure that I'll add something to build up custom values like Uri.

As a side node, you don't need to add [uri] to your help text, just use MetaValue="URI"...

If you'd like to propose how you'd see it implemented, please add a comment.

@mac2000
Copy link
Author

mac2000 commented Jul 29, 2015

For non simple types, commandline may check (reflection?) is there constructor with a single string parameter available and if so try instantiate an object, if any exception occurs throw it to user.

Something like this probably may solve this and other similar requests.

@gsscoder
Copy link
Owner

@mac2000, mmm... this could be a possible solution. Thanks for putting it in evidence.

It will only work with types that have a (also) a ctor that accepts a string, since the library doesn't have knowledge beyond basic types, nullable, f# option and sequences.

I think it could be a first step before adding an explicit machinery to convert string to complex values. 👍

Other opinions? cc/ @Thilas @mizipzor @nemec @gimmemoore

@gsscoder gsscoder self-assigned this Jul 31, 2015
gsscoder added a commit that referenced this issue Jul 31, 2015
gsscoder added a commit that referenced this issue Jul 31, 2015
@gsscoder
Copy link
Owner

@mac2000, Version 2.0.211-alpha (also on NuGet) solves this issue. Please check and close the issue, if OK (or tell me what's wrong).

@mac2000
Copy link
Author

mac2000 commented Jul 31, 2015

Confirming, it works.

As a benefit now we can do some crazy stuffs like this:

class Options
{
    [Option('e', "Endpoint", HelpText = "Endpoint, e.g.: http://localhost:9200", MetaValue = "URI")]
    public Uri Endpoint { get; set; }

    [Option('d', "LastModifiedDateTime", HelpText = "Last modified datetime, e.g.: 2015-07-31 11:51", MetaValue = "DateTime")]
    public DateTime LastModifiedDateTime { get; set; }

    [Option('c', "SqlConnection", HelpText = "Connection string, e.g.: Data Source=.;Initial Catalog=Play;Integrated Security=True", MetaValue = "string")]
    public SqlConnection SqlConnection { get; set; }
}

Checked all things working, so closing issue.

BTW: Other possible solution may be to add SetterMethod to OptionAttribute which may be then used for complex types that can not be instantiated from string.

@mac2000 mac2000 closed this as completed Jul 31, 2015
@mac2000
Copy link
Author

mac2000 commented Jul 31, 2015

PS: Just checked yet more crazy scenario

interface IAction
{
    void DoTheWork();
}

class FooAction : IAction
{
    public void DoTheWork()
    {
        Console.WriteLine("Foo action being called");
    }
}

class BarAction : IAction
{
    public void DoTheWork()
    {
        Console.WriteLine("Bar action being called");
    }
}

class Action : IAction
{
    public IAction ResolvedAction { get; set; }

    public Action(string action)
    {
        ResolvedAction = Resolve(action);
    }

    public void DoTheWork()
    {
        ResolvedAction.DoTheWork();
    }

    public static IAction Resolve(string action)
    {
        switch (action.Trim().ToLower())
        {
            case "foo": return new FooAction();
            case "bar": return new BarAction();
            default: throw new FormatException(string.Format("Unknown action {0}", action));
        }
    }


}

class Options
{
    [Option('a', "Action", HelpText = "Action", MetaValue = "Foo|Bar")]
    public Action Action { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Parser.Default.ParseArguments<Options>(args).WithParsed(Run);
    }

    static void Run(Options options)
    {
        options.Action.DoTheWork();
    }
}

all works like a charm, thank you @gsscoder for your work

@gsscoder
Copy link
Owner

@mac2000, you're wellcome.

Yes, passing a string to a custom type opens various possibilities; anyway (saying this in general...) I suggest to not abuse such feature and eventually wait the new machinery to create complex instance.

Have nice day :)

@nemec
Copy link
Collaborator

nemec commented Aug 1, 2015

@mac2000 one way to improve on the more complex scenario would be to allow Options to be annotated with a custom TypeConverterAttribute. If CommandLine sees that an option has that attribute, it could use the custom converter instead of the default one. For example (and this example isn't really useful), you could write a custom 'int' converter that takes a date/time (myapp.exe -s 2015-07-12T12:00:00Z) and converts it into UNIX time:

[Option('s')]
[TypeConverter(typeof(UnixTimeConverter))]
public int StartTime { get; set; }

But maybe that's what @gsscoder is talking about when he says "wait for new machinery" :)

@gsscoder
Copy link
Owner

gsscoder commented Aug 1, 2015

@nemec, yes, I've to say that your contribute to discussion is always interesting. :)

Your solution is more type safe, in the other post if I'm not wrong I was proposing another string property for Option attribute with the name of an option's class property get that returns a conversion function (as a System.Func).

Concept it similar but TypeConverter is clenaer, I like it more. 👍

I'm also agree to use another attribute instead of bloating Option and Value attributes properties.

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

No branches or pull requests

3 participants