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

Adds support for user defined value parsers #59

Merged
merged 5 commits into from
Mar 21, 2018

Conversation

atruskie
Copy link
Contributor

@atruskie atruskie commented Mar 11, 2018

Closes #51.

This commit allows users to supply their own value parsers via the ValueParsers property on CommandLineApplication. The bulk of the changed files are small changes like converting all the current value parser implementations to the updated interface.

One side-effect of this change is that ValueParserProvider is no longer a singleton, but instead has state for the duration of the CommandLineApplication.

Questions:

  • This change I feel ties nicely in with Design: builder API for parsing args into .NET types #37, should we expand scope?
    • Because of this, I exposed the ValueParsers property on CommandLineApplication and not CommandLineApplication<T>
  • ValueParserProvider and IValueParser are no longer internal utilities - should I move the files out of the internal folder?
  • Should we simplify the ValueTupleParserProvider code? It is just a (non-)special case of an ordinary value parser
  • I was forced to change the ValueParseProvider to a non-singleton (parallelism in tests affected singleton state). I don't like passing the ValueParserProvider around as arguments everywhere but I thought it better than managing god states.

Assumptions:

  • I assumed it would be best to update the existing value parser providers so all value parsers (predefined and user-defined) use the same interface

Other notes:

  • although tedious, leaving the exception inside the Parse method allows users to customize the error string, useful for example to allow internationalization of error messages
  • I added an additional public API AddRange to ValueParserProvider. I know this wasn't agreed on so I don't mind removing it.
  • I changed the string value for an exception message and forgot to save the file. This is why the tests fail. They all pass on my machine. Will fix test when addressing feedback. Fixed in 3a57425

Closes natemcmaster#51.

This commit allows users to supply their own value parsers via the `ValueParsers` property on `CommandLineApplication`. The bulk of the changed files are small changes like converting all the current value parser implementations to the updated interface.

One side-effect of this change is that `ValueParserProvider` is no longer a singleton, but instead has state for the duration of the `CommandLineApplication`.
@natemcmaster natemcmaster self-assigned this Mar 12, 2018
@rubenprins
Copy link

Any reason TypeConverters aren't used? If they would be supported, passing/conversion code could be shared more easily across projects (e.g. with MVC model binding).

@atruskie
Copy link
Contributor Author

Hi @rubenprins. While I'm aware of TypeConverters we haven't discussed it in the design in #51. I think the simplest answer is the that the changes we made represent the smallest changes needed to make the existing value parsers that were there public.

Additionally, the interface is pretty heavy. We don't need the two-way conversion or a bunch of other stuff. Because we went with an interface implementation you could adapt your existing MVC model binders by inheriting from that same interface.

Though there is something to be said for not re-inventing the wheel.

I personally do not have a preference.

@natemcmaster
Copy link
Owner

Just wanted to let you know I saw this. I'll take a closer look next week. This week is pretty busy for me.

@rubenprins using TypeConverter is a good suggestion, but I agree with what @atruskie said. We wanted a minimal interface of our own to make it easy for devs to implement their own type parsers without the heavy TypeConverter interface. That said, you should be able to implement a TypeConverter adapter if you wanted to re-use your TypeConverters for command-line parsing.

@natemcmaster
Copy link
Owner

Also @atruskie - I didn't look closely, but it looks like some unit tests are failing

@natemcmaster natemcmaster added this to the 2.2.0 milestone Mar 14, 2018
@rubenprins
Copy link

@natemcmaster one advantage I see when using the TypeConverter infrastructure, is that you can annotate either the types of the properties or the properties themselves. With a type based ValueParserProvider, you lose that annotation ability (the ValueParserProvider does not receive the original PropertyInfo).

For example, it's not possible to support a chmod like option (octal based) with regular integers for the other properties. With something like [TypeConverter(typeof(ChmodConverter))] on only that specific property, that would be possible.

Note that if the ValueParserProvider were replaceable and to expose a virtual GetParser method to receive the command option's PropertyInfo, I could implement this myself. At the moment, it's not really possible to set up attribute based parsers/converters.

@natemcmaster
Copy link
Owner

@rubenprins let's use #62 to continue this. I think there are some things we can do to support TypeConverters.

Copy link
Owner

@natemcmaster natemcmaster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great I just had one question.

To answer yours...

This change I feel ties nicely in with #37, should we expand scope?

Let's keep this PR scoped as is. Still not sure I want to do #37 yet.

should I move the files out of the internal folder?

Yes please :)

Should we simplify the ValueTupleParserProvider code?

Can stay as is for now, but feel free to send a follow-up PR to cleanup if you want.

was forced to change the ValueParseProvider to a non-singleton

Okay with me.

added an additional public API AddRange to ValueParserProvider

Thanks. I think it's valuable enough to keep.

/// <summary>
/// Gets the default value parser provider.
/// <para>
/// The value parsers control how arugment values are converted from strings to other types. Additional value
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: argument

{
get
{
throw new InvalidOperationException($"{nameof(NullableValueParser)} does not have a target type");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this just return _enumType? Also, why does it say NullableValueParser?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made it return _enumType.

I chose an error because Enums are special cases and the EnumParser never uses TargetType.

Fixed spelling, removed usage of `this` (inconsistent with project style), changed EnumParser's target type a valid value - even though it is not used.

Related to natemcmaster#59
@atruskie
Copy link
Contributor Author

I moved the files but I was hoping for a little bit of guidance on placement or naming (sorry for being unclear). I kept the move changes separate so they're easy to track.

Let me know if you want me to do more or to squash first three commits etc..

@natemcmaster
Copy link
Owner

I wasn't too worried about namespaces and organization when this code was all internal, but now that I think about it, IValueParser and ValueParserProvider probably belong in this namespace: McMaster.Extensions.CommandLineUtils.Abstractions. Can you put IValueParser.cs and ValueParserProvider.cs in src/CommandLineUtils/Abstractions/ to match that namespace?

@atruskie
Copy link
Contributor Author

@natemcmaster done. Should I squash?

@natemcmaster
Copy link
Owner

No need. I can squash via GitHub for you.

Thanks for your effort on this. I sincerely appreciate your help. I'll be preparing the 2.2.0-rc release soon. I'll make sure to add your effort to the release notes.

@natemcmaster natemcmaster merged commit e89ac45 into natemcmaster:master Mar 21, 2018
@atruskie atruskie deleted the custom-value-parsers branch March 21, 2018 02:27
@atruskie
Copy link
Contributor Author

My pleasure @natemcmaster. I appreciate that you've adopted and evolved this library! It has certainly made my life easier.

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

Successfully merging this pull request may close these issues.

Support for custom value parsers
3 participants