Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: gsscoder/commandline
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: deng0/commandline
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 1 commit
  • 6 files changed
  • 1 contributor

Commits on Aug 10, 2017

  1. fixed performance issue and adjusted ParseArguments overloads

    - fixed serious performance issue by adding some more Memorize() calls
    - adjusted ParseArguments<T>(factory, args) overload. T now must be the correct type.
    - added two more ParseArguments overloads
    dego committed Aug 10, 2017
    Copy the full SHA
    95ff7f6 View commit details
24 changes: 12 additions & 12 deletions src/CommandLine/Core/InstanceBuilder.cs
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ namespace CommandLine.Core
static class InstanceBuilder
{
public static ParserResult<T> Build<T>(
Type typeInfo,
Maybe<Func<T>> factory,
Func<IEnumerable<string>, IEnumerable<OptionSpecification>, Result<IEnumerable<Token>, Error>> tokenizer,
IEnumerable<string> arguments,
@@ -25,25 +26,24 @@ public static ParserResult<T> Build<T>(
CultureInfo parsingCulture,
IEnumerable<ErrorType> nonFatalErrors)
{
var typeInfo = factory.MapValueOrDefault(f => f().GetType(), typeof(T));
var isMutable = typeInfo.IsMutable();

if (!isMutable && factory.IsJust())
{
throw new ArgumentException("Cannot use factor for immutable types.", "factory");
}

var specProps = typeInfo.GetSpecifications(pi => SpecificationProperty.Create(
Specification.FromProperty(pi), pi, Maybe.Nothing<object>()));
Specification.FromProperty(pi), pi, Maybe.Nothing<object>())).Memorize();

var specs = from pt in specProps select pt.Specification;

var optionSpecs = specs
.ThrowingValidate(SpecificationGuards.Lookup)
.OfType<OptionSpecification>();

Func<T> makeDefault = () =>
typeof(T).IsMutable()
? factory.MapValueOrDefault(f => f(), Activator.CreateInstance<T>())
: ReflectionHelper.CreateDefaultImmutableInstance<T>(
(from p in specProps select p.Specification.ConversionType).ToArray());

Func<IEnumerable<Error>, ParserResult<T>> notParsed =
errs => new NotParsed<T>(makeDefault().GetType().ToTypeInfo(), errs);
errs => new NotParsed<T>(typeInfo.ToTypeInfo(), errs);

Func<ParserResult<T>> buildUp = () =>
{
@@ -78,11 +78,11 @@ public static ParserResult<T> Build<T>(
.FromOptionSpecification());

var specPropsWithValue =
optionSpecPropsResult.SucceededWith().Concat(valueSpecPropsResult.SucceededWith());
optionSpecPropsResult.SucceededWith().Concat(valueSpecPropsResult.SucceededWith()).Memorize();

Func<T> buildMutable = () =>
{
var mutable = factory.MapValueOrDefault(f => f(), Activator.CreateInstance<T>());
var mutable = factory.MapValueOrDefault(f => f(), (T)Activator.CreateInstance(typeInfo));
mutable =
mutable.SetProperties(specPropsWithValue, sp => sp.Value.IsJust(), sp => sp.Value.FromJustOrFail())
.SetProperties(
@@ -111,7 +111,7 @@ join sp in specPropsWithValue on prms.Name.ToLower() equals sp.Property.Name.ToL
return immutable;
};

var instance = typeInfo.IsMutable() ? buildMutable() : buildImmutable();
var instance = isMutable ? buildMutable() : buildImmutable();

var validationErrors = specPropsWithValue.Validate(SpecificationPropertyRules.Lookup(tokens));

6 changes: 3 additions & 3 deletions src/CommandLine/Core/InstanceChooser.cs
Original file line number Diff line number Diff line change
@@ -52,11 +52,11 @@ private static ParserResult<object> MatchVerb(
CultureInfo parsingCulture,
IEnumerable<ErrorType> nonFatalErrors)
{
verbs = verbs.Memorize();
return verbs.Any(a => nameComparer.Equals(a.Item1.Name, arguments.First()))
? InstanceBuilder.Build(
Maybe.Just<Func<object>>(
() =>
verbs.Single(v => nameComparer.Equals(v.Item1.Name, arguments.First())).Item2.AutoDefault()),
verbs.Single(v => nameComparer.Equals(v.Item1.Name, arguments.First())).Item2,
Maybe.Nothing<Func<object>>(),
tokenizer,
arguments.Skip(1),
nameComparer,
4 changes: 3 additions & 1 deletion src/CommandLine/Core/OptionMapper.cs
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ public static Result<
Func<IEnumerable<string>, Type, bool, Maybe<object>> converter,
StringComparer comparer)
{
options = options.Memorize();

var sequencesAndErrors = propertyTuples
.Select(
pt =>
@@ -43,7 +45,7 @@ select Tuple.Create(
((OptionSpecification)pt.Specification).FromOptionSpecification()))))
: Tuple.Create(pt, Maybe.Nothing<Error>());
}
);
).Memorize();
return Result.Succeed(
sequencesAndErrors.Select(se => se.Item1),
sequencesAndErrors.Select(se => se.Item2).OfType<Just<Error>>().Select(se => se.Value));
2 changes: 1 addition & 1 deletion src/CommandLine/Core/Tokenizer.cs
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ public static Result<IEnumerable<Token>, Error> Tokenize(
select token)
.Memorize();

var normalized = normalize(tokens);
var normalized = normalize(tokens).Memorize();

var unkTokens = (from t in normalized where t.IsName() && nameLookup(t.Text) == NameLookupResult.NoOptionFound select t).Memorize();

3 changes: 3 additions & 0 deletions src/CommandLine/Core/ValueMapper.cs
Original file line number Diff line number Diff line change
@@ -18,6 +18,9 @@ public static Result<
IEnumerable<string> values,
Func<IEnumerable<string>, Type, bool, Maybe<object>> converter)
{
specProps = specProps.Memorize();
values = values.Memorize();

var propAndErrors = MapValuesImpl(specProps, values, converter);

return Result.Succeed(
63 changes: 57 additions & 6 deletions src/CommandLine/Parser.cs
Original file line number Diff line number Diff line change
@@ -87,13 +87,10 @@ public ParserResult<T> ParseArguments<T>(IEnumerable<string> args)
{
if (args == null) throw new ArgumentNullException("args");

var factory = typeof(T).IsMutable()
? Maybe.Just<Func<T>>(Activator.CreateInstance<T>)
: Maybe.Nothing<Func<T>>();

return MakeParserResult(
InstanceBuilder.Build(
factory,
typeof(T),
Maybe.Nothing<Func<T>>(),
(arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings),
args,
settings.NameComparer,
@@ -117,11 +114,11 @@ public ParserResult<T> ParseArguments<T>(Func<T> factory, IEnumerable<string> ar
where T : new()
{
if (factory == null) throw new ArgumentNullException("factory");
if (!typeof(T).IsMutable()) throw new ArgumentException("factory");
if (args == null) throw new ArgumentNullException("args");

return MakeParserResult(
InstanceBuilder.Build(
typeof(T),
Maybe.Just(factory),
(arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings),
args,
@@ -161,6 +158,60 @@ public ParserResult<object> ParseArguments(IEnumerable<string> args, params Type
settings);
}

/// <summary>
/// Parses a string array of command line arguments and sets the properties of the provided instance.
/// Grammar rules are defined decorating public properties with appropriate attributes.
/// </summary>
/// <param name="instance">The instance.</param>
/// <param name="args">A <see cref="System.String"/> array of command line arguments, normally supplied by application entry point.</param>
/// <returns>A <see cref="CommandLine.ParserResult{T}"/> containing an instance of the specified type with parsed values
/// and a sequence of <see cref="CommandLine.Error"/>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if one or more arguments are null.</exception>
public ParserResult<T> ParseArguments<T>(T instance, IEnumerable<string> args)
{
if (instance == null) throw new ArgumentNullException("instance");
if (args == null) throw new ArgumentNullException("args");

return MakeParserResult(
InstanceBuilder.Build(
instance.GetType(),
Maybe.Just<Func<T>>(() => instance),
(arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings),
args,
settings.NameComparer,
settings.CaseInsensitiveEnumValues,
settings.ParsingCulture,
HandleUnknownArguments(settings.IgnoreUnknownArguments)),
settings);
}

/// <summary>
/// Parses a string array of command line arguments constructing values in an instance the specified type.
/// Grammar rules are defined decorating public properties with appropriate attributes.
/// </summary>
/// <param name="type">The type of the instance to create.</param>
/// <param name="args">A <see cref="System.String"/> array of command line arguments, normally supplied by application entry point.</param>
/// <returns>A <see cref="CommandLine.ParserResult{Object}"/> containing an instance of the specified type with parsed values
/// and a sequence of <see cref="CommandLine.Error"/>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if one or more arguments are null.</exception>
public ParserResult<object> ParseArguments(Type type, IEnumerable<string> args)
{
if (type == null) throw new ArgumentNullException("type");
if (args == null) throw new ArgumentNullException("args");

return MakeParserResult(
InstanceBuilder.Build(
type,
Maybe.Nothing<Func<object>>(),
(arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings),
args,
settings.NameComparer,
settings.CaseInsensitiveEnumValues,
settings.ParsingCulture,
HandleUnknownArguments(settings.IgnoreUnknownArguments)),
settings);
}

/// <summary>
/// Frees resources owned by the instance.
/// </summary>