Skip to content

Commit

Permalink
feature: update CommandOption/Argument.value to return DefaultValue (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
natemcmaster authored Jan 11, 2021
1 parent 9ff8c22 commit 8c2a3d2
Show file tree
Hide file tree
Showing 17 changed files with 341 additions and 79 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<PropertyGroup>
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
<WarningsNotAsErrors>$(WarningsNotAsErrors);1591</WarningsNotAsErrors>
<LangVersion>8.0</LangVersion>
<LangVersion>9.0</LangVersion>
<Nullable>annotations</Nullable>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)src\StrongName.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
Expand Down
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,19 @@ using McMaster.Extensions.CommandLineUtils;
var app = new CommandLineApplication();

app.HelpOption();
var optionSubject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
var optionRepeat = app.Option<int>("-n|--count <N>", "Repeat", CommandOptionType.SingleValue);

var subject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
subject.DefaultValue = "world";

var repeat = app.Option<int>("-n|--count <N>", "Repeat", CommandOptionType.SingleValue);
repeat.DefaultValue = 1;

app.OnExecute(() =>
{
var subject = optionSubject.HasValue()
? optionSubject.Value()
: "world";

var count = optionRepeat.HasValue() ? optionRepeat.ParsedValue : 1;
for (var i = 0; i < count; i++)
for (var i = 0; i < repeat.ParsedValue; i++)
{
Console.WriteLine($"Hello {subject}!");
Console.WriteLine($"Hello {subject.Value()}!");
}
return 0;
});

return app.Execute(args);
Expand Down
9 changes: 3 additions & 6 deletions docs/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,12 @@ public class Program
var app = new CommandLineApplication();

app.HelpOption();
var optionSubject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
var subject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
subject.DefaultValue = "world";

app.OnExecute(() =>
{
var subject = optionSubject.HasValue()
? optionSubject.Value()
: "world";

Console.WriteLine($"Hello {subject}!");
Console.WriteLine($"Hello {subject.Value()}!");
return 0;
});

Expand Down
6 changes: 2 additions & 4 deletions docs/samples/custom-attribute/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ public void Apply(ConventionContext context, MemberInfo member)
if (member is FieldInfo field)
{
var opt = context.Application.Option("--working-dir", "The working directory", CommandOptionType.SingleOrNoValue);
opt.DefaultValue = context.Application.WorkingDirectory;
context.Application.OnParsingComplete(_ =>
{
var cwd = opt.HasValue()
? opt.Value()
: context.Application.WorkingDirectory;
field.SetValue(context.ModelAccessor.GetModel(), cwd);
field.SetValue(context.ModelAccessor.GetModel(), opt.Value());
});
}
}
Expand Down
16 changes: 7 additions & 9 deletions docs/samples/helloworld-async/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,22 @@
var app = new CommandLineApplication();

app.HelpOption();
var optionSubject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
var optionRepeat = app.Option<int>("-n|--count <N>", "Repeat", CommandOptionType.SingleValue);
var subject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
subject.DefaultValue = "world";

var repeat = app.Option<int>("-n|--count <N>", "Repeat", CommandOptionType.SingleValue);
repeat.DefaultValue = 1;

app.OnExecuteAsync(async cancellationToken =>
{
var subject = optionSubject.HasValue()
? optionSubject.Value()
: "world";
var count = optionRepeat.HasValue() ? optionRepeat.ParsedValue : 1;
for (var i = 0; i < count; i++)
for (var i = 0; i < repeat.ParsedValue; i++)
{
Console.Write($"Hello");
// Pause for dramatic effect
await Task.Delay(2000, cancellationToken);
Console.WriteLine($" {subject}!");
Console.WriteLine($" {subject.Value()}!");
}
});

Expand Down
1 change: 1 addition & 0 deletions docs/samples/helloworld/HelloWorld.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
16 changes: 6 additions & 10 deletions docs/samples/helloworld/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
var app = new CommandLineApplication();

app.HelpOption();
var optionSubject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
var optionRepeat = app.Option<int>("-n|--count <N>", "Repeat", CommandOptionType.SingleValue);
var subject = app.Option("-s|--subject <SUBJECT>", "The subject", CommandOptionType.SingleValue);
subject.DefaultValue = "world";
var repeat = app.Option<int?>("-n|--count <N>", "Repeat", CommandOptionType.SingleValue);
repeat.DefaultValue = 1;

app.OnExecute(() =>
{
var subject = optionSubject.HasValue()
? optionSubject.Value()
: "world";
var count = optionRepeat.HasValue() ? optionRepeat.ParsedValue : 1;
for (var i = 0; i < count; i++)
for (var i = 0; i < repeat.ParsedValue; i++)
{
Console.WriteLine($"Hello {subject}!");
Console.WriteLine($"Hello {subject.Value()}!");
}
return 0;
});

return app.Execute(args);
16 changes: 13 additions & 3 deletions src/CommandLineUtils/CommandArgument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,25 @@ public class CommandArgument
/// <summary>
/// All values specified, if any.
/// </summary>
public IReadOnlyList<string?> Values => _values;
public IReadOnlyList<string?> Values
{
get
{
if (_values.Count == 0 && DefaultValue != null)
{
return new List<string?> { DefaultValue };
}
return _values;
}
}

/// <summary>
/// Allow multiple values.
/// </summary>
public bool MultipleValues { get; set; }

/// <summary>
/// The first value from <see cref="Values"/>, if any.
/// The first value from <see cref="Values"/>, if any, or <see cref="DefaultValue" />.
/// </summary>
public string? Value => Values.FirstOrDefault();

Expand All @@ -54,7 +64,7 @@ public class CommandArgument
public string? DefaultValue { get; set; }

/// <summary>
/// True if this argument has been assigned values.
/// True when <see cref="Values"/> is not empty or when a <see cref="DefaultValue" /> is given.
/// </summary>
public bool HasValue => Values.Any();

Expand Down
39 changes: 33 additions & 6 deletions src/CommandLineUtils/CommandArgument{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public class CommandArgument<T> : CommandArgument, IInternalCommandParamOfT
{
private readonly List<T> _parsedValues = new List<T>();
private readonly IValueParser<T> _valueParser;
private T _defaultValue;
private bool _hasBeenParsed;
private bool _hasDefaultValue;
private T? _defaultValue;

/// <summary>
/// Initializes a new instance of <see cref="CommandArgument{T}" />
Expand All @@ -30,36 +32,53 @@ public CommandArgument(IValueParser<T> valueParser)
{
_valueParser = valueParser ?? throw new ArgumentNullException(nameof(valueParser));
UnderlyingType = typeof(T);
SetBaseDefaultValue(default);
}

/// <summary>
/// The parsed value.
/// </summary>
public T ParsedValue => _parsedValues.FirstOrDefault();
public T ParsedValue => ParsedValues.FirstOrDefault();

/// <summary>
/// All parsed values;
/// </summary>
public IReadOnlyList<T> ParsedValues => _parsedValues;
public IReadOnlyList<T> ParsedValues
{
get
{
if (!_hasBeenParsed)
{
((IInternalCommandParamOfT)this).Parse(CultureInfo.CurrentCulture);
}

if (_parsedValues.Count == 0 && _hasDefaultValue)
{
return new[] { DefaultValue };
}

return _parsedValues;
}
}

/// <summary>
/// The default value of the argument.
/// </summary>
public new T DefaultValue
public new T? DefaultValue
{
get => _defaultValue;
set
{
_hasDefaultValue = value != null;
_defaultValue = value;
SetBaseDefaultValue(value);
}
}

void IInternalCommandParamOfT.Parse(CultureInfo culture)
{
_hasBeenParsed = true;
_parsedValues.Clear();
foreach (var t in Values)
foreach (var t in base._values)
{
_parsedValues.Add(_valueParser.Parse(Name, t, culture));
}
Expand All @@ -79,5 +98,13 @@ void SetBaseDefaultValue(T value)
}
}
}

/// <inheritdoc />
public override void Reset()
{
_hasBeenParsed = false;
_parsedValues.Clear();
base.Reset();
}
}
}
21 changes: 14 additions & 7 deletions src/CommandLineUtils/CommandOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,17 @@ internal CommandOption(CommandOptionType type)
/// <summary>
/// Any values found during parsing, if any.
/// </summary>
public IReadOnlyList<string?> Values => _values;
public IReadOnlyList<string?> Values
{
get
{
if (_values.Count == 0 && DefaultValue != null)
{
return new List<string?> { DefaultValue };
}
return _values;
}
}

/// <summary>
/// The default value of the option.
Expand Down Expand Up @@ -171,7 +181,7 @@ public bool TryParse(string? value)
}

/// <summary>
/// True when <see cref="Values"/> is not empty.
/// True when <see cref="Values"/> is not empty or when a <see cref="DefaultValue" /> is given.
/// </summary>
/// <returns></returns>
public bool HasValue()
Expand All @@ -180,13 +190,10 @@ public bool HasValue()
}

/// <summary>
/// Returns the first element of <see cref="Values"/>, if any.
/// Returns the first element of <see cref="Values"/>, if any, or <see cref="DefaultValue" />.
/// </summary>
/// <returns></returns>
public string? Value()
{
return HasValue() ? Values[0] : null;
}
public string? Value() => Values.FirstOrDefault();

/// <summary>
/// Generates the template string in the format "-{Symbol}|-{Short}|--{Long} &lt;{Value}&gt;" for display in help text.
Expand Down
Loading

0 comments on commit 8c2a3d2

Please sign in to comment.