Code Monkey home page Code Monkey logo

Comments (14)

natemcmaster avatar natemcmaster commented on June 15, 2024

Marking as help wanted. Let me know if you want to tackle one of these and let's define an API shape first.

from commandlineutils.

ninjaboy avatar ninjaboy commented on June 15, 2024

Is there currently a way to specify required command argument type using builder API?
E.g. I want to add a command argument which will be integer (and possibly be within the range)?

from commandlineutils.

natemcmaster avatar natemcmaster commented on June 15, 2024

Is there currently a way to specify required command argument type using builder API?

Not yet. This is one of the validators I wanted to add for 2.2. Would definitely accept a PR to add something like IValidationBuilder.Range(int min, int max).

from commandlineutils.

ninjaboy avatar ninjaboy commented on June 15, 2024

from commandlineutils.

natemcmaster avatar natemcmaster commented on June 15, 2024

I think its a good idea. My current thinking is that this would require implementing a mix of the builder API and the attribute-based command-line parsing. I have ideas in my head about how we could introduce CommandArgument<T> to make this possible. I'll try to sketch down those ideas in a separate issue to make sure the design would actually work.

from commandlineutils.

ninjaboy avatar ninjaboy commented on June 15, 2024

from commandlineutils.

natemcmaster avatar natemcmaster commented on June 15, 2024

Ok, here are my ideas: #37

from commandlineutils.

peterwurzinger avatar peterwurzinger commented on June 15, 2024

Hi,

Since I needed that feature recently, I'd like to implement validation of CommandArguments to check whether they are contained in a predefined set of values - e.g. string-arrays or enums.
I will keep track of this in my own fork in https://github.com/peterwurzinger/CommandLineUtils/tree/SetValidation and open a PR when I'm finished.

Regards,
Peter

from commandlineutils.

natemcmaster avatar natemcmaster commented on June 15, 2024

@peterwurzinger I had started implementing this kind of validation too. I struggled to come up with good API names that I felt communicated well what the validator was doing. Here is what I had so far:

// attributes
class MyOptions
{
   [Option]
   [Values("low", "normal", "high", IgnoreCase = false)]  // IgnoreCase defaults to true
   public string Importance { get; }
}

// builder api
var app = new CommandLineApplication();
app.Option("--importance", CommandOptionType.SingleValue)
  .Accepts().Values("low", "normal", "high", ignoreCase: false);
// ignoreCase defaults to true

I had also intended on adding support for automatically parsing enum types.

enum Importance
{
   Low,
   Medium,
   High
}

class MyOptions
{
   [Option]
   public Importance Importance { get; }
}

What do you think? How does this compare with what you've drafted?

from commandlineutils.

peterwurzinger avatar peterwurzinger commented on June 15, 2024

@natemcmaster It compares quite well, since your implementation is almost identical to mine in the most parts 😄
I am quite bad at API-naming, since english isn't my first language, but i named the corresponding attribute IsInSetAttribute to fit to other custom attributes like FileExists or DirectoryExists.
To support enum validation I added an inherited attribute named IsInEnumAttribute which only passes the base-constructor all enum-names of a defined enum type. I don't know if that's the way to go, but it's okay as a first shot imho. I'm only handling string-values at the moment...

My blocking issue, which prevents me from going further, is the ambiguity regarding CommandOption<TValue> and CommandArgument<TValue> and how those will affect the general architecture. I'll just write down my thoughts on this in context of validation:
Since (Validation)Attributes can't be generic this leads to the problem that they need to interpret object-typed values as the generic target type of the respective option or argument without having compile time safety. I understand that validation attributes are a first level citizen of this library, but with generic arguments/options there are a two main questions to answer:

  • Should attribute based validation be restricted to non-generic validators?
  • If not, is there a way to make generic implementations of IValidator<T> (which it would need as a consequence of generic options/arguments, imho) easily accessible through attribute-API just like there is the other way round as ValidationBuilder.Satisfies<ValidationAttribute>(...) ?

To make that clear I'll give a short example:

class FooValidator<TValue> : IValidator<TValue>
{
	//Insert highly complex, generic validation logic here
}

static class ValidationExtensions {
	static IValidationBuilder<TValue> Foo<TValue>(this IValidationBuilder<TValue> builder)
	{
		//The easy part
		return builder.Use(new FooValidator<TValue>());
	}
}

class FooAttribute : ValidationAttribute
{
	override ValidationResult IsValid(object value, ValidationContext validationContext)
	{
		//Instantiate a generic validator?
	}
}

What are your thoughts on this?

from commandlineutils.

natemcmaster avatar natemcmaster commented on June 15, 2024

It compares quite well, since your implementation is almost identical to mine in the most parts

Ok, if what I proposed works for you, let's go with ValuesAttribute. I also want to implement binding to enums automatically so we don't need something like EnumAttribute. You can already specify OptionAttribute on int, bool, float, and IList<T> properties. Using types other than string implies some validation is required.

My blocking issue, which prevents me from going further, is the ambiguity regarding CommandOption<TValue> and CommandArgument<TValue>

I assume you're referring to #37. My current thinking is that conversion from string to TValue will happen first, so ValidationAttribute.IsValid(object value) would be called only if the parsing is successful. After that, ValidationAttribute implementations can use type checks and pattern matching to do the right thing.

class FooAttribute : ValidationAttribute
{
    override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        int count;
        if (value is int i)
        {
            count = i;
        }
        else if (value is string str && !int.TryParse(str, out count))
        {
            return new ValidationResult("Could not parse value to an integer");
        }

        return count > 5
            ? ValidationResult.Success
            : new ValidationResult("Value must be greater than 5");
    }
}

from commandlineutils.

natemcmaster avatar natemcmaster commented on June 15, 2024

I've added validators for enums, a set of strings, minlength, max length, file paths, and more. Not planning to add anymore at this point in the 2.2.0 release. If you want another validator built in, open a new issue.

12262e3 - enum validation
f6a7768 - set of strings
4f475f8 - minlength, maxlenght, and regex
b2a8439- file path validators

from commandlineutils.

t03apt avatar t03apt commented on June 15, 2024

Hi!
@natemcmaster It would be great to have nullable enums as well. Otherwise I can't figure out if a value was given for an optional parameter.
For example:

enum Importance
{
   Low,
   Medium,
   High
}

class MyOptions
{
   [Option]
   public Importance? Importance { get; }
}

from commandlineutils.

t03apt avatar t03apt commented on June 15, 2024

Never mind. I just figured that I can do something like this:

enum Importance
{
   Low,
   Medium,
   High
}

class MyOptions
{
   [Option]
   public Importance Importance { get; } = Importance.Medium;
}

I just wanted to be able to set some defaults. Btw, Option attribute could also have a Default property.
This library have that: https://github.com/commandlineparser/commandline

from commandlineutils.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.