Skip to content

Adds support for user defined value parsers - #59

Merged
natemcmaster merged 5 commits into
natemcmaster:masterfrom
atruskie:custom-value-parsers
Mar 21, 2018
Merged

Adds support for user defined value parsers#59
natemcmaster merged 5 commits into
natemcmaster:masterfrom
atruskie:custom-value-parsers

Conversation

@atruskie

@atruskie atruskie commented Mar 11, 2018

Copy link
Copy Markdown
Contributor

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
Copy Markdown

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown

@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
Copy Markdown
Owner

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

@natemcmaster natemcmaster left a comment

Copy link
Copy Markdown
Owner

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor Author

@natemcmaster done. Should I squash?

@natemcmaster

Copy link
Copy Markdown
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
Copy Markdown
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