Skip to content

Commit d16d24c

Browse files
authored
Merge pull request #289 from PerthHackers/develop
Remerge 274 directly into master
2 parents 68d46c7 + 6ce423d commit d16d24c

File tree

8 files changed

+151
-22
lines changed

8 files changed

+151
-22
lines changed

README.md

+61-16
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,43 @@ You can utilize the parser library in several ways:
4646
1. Create a class to define valid options, and to receive the parsed options.
4747
2. Call ParseArguments with the args string array.
4848

49+
C# Quick Start:
50+
51+
```csharp
52+
using System;
53+
using CommandLine;
54+
55+
namespace QuickStart
56+
{
57+
class Program
58+
{
59+
public class Options
60+
{
61+
[Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")]
62+
public bool Verbose { get; set; }
63+
}
64+
65+
static void Main(string[] args)
66+
{
67+
Parser.Default.ParseArguments<Options>(args)
68+
.WithParsed<Options>(o =>
69+
{
70+
if (o.Verbose)
71+
{
72+
Console.WriteLine($"Verbose output enabled. Current Arguments: -v {o.Verbose}");
73+
Console.WriteLine("Quick Start Example! App is in Verbose mode!");
74+
}
75+
else
76+
{
77+
Console.WriteLine($"Current Arguments: -v {o.Verbose}");
78+
Console.WriteLine("Quick Start Example!");
79+
}
80+
});
81+
}
82+
}
83+
}
84+
```
85+
4986
C# Examples:
5087

5188
```csharp
@@ -55,10 +92,14 @@ class Options
5592
public IEnumerable<string> InputFiles { get; set; }
5693

5794
// Omitting long name, defaults to name of property, ie "--verbose"
58-
[Option(Default = false, HelpText = "Prints all messages to standard output.")]
95+
[Option(
96+
Default = false,
97+
HelpText = "Prints all messages to standard output.")]
5998
public bool Verbose { get; set; }
60-
61-
[Option("stdin", Default = false, HelpText = "Read from stdin")]
99+
100+
[Option("stdin",
101+
Default = false
102+
HelpText = "Read from stdin")]
62103
public bool stdin { get; set; }
63104

64105
[Value(0, MetaName = "offset", HelpText = "File offset.")]
@@ -79,7 +120,7 @@ F# Examples:
79120
type options = {
80121
[<Option('r', "read", Required = true, HelpText = "Input files.")>] files : seq<string>;
81122
[<Option(HelpText = "Prints all messages to standard output.")>] verbose : bool;
82-
[<Option(DefaultValue = "русский", HelpText = "Content language.")>] language : string;
123+
[<Option(Default = "русский", HelpText = "Content language.")>] language : string;
83124
[<Value(0, MetaName="offset", HelpText = "File offset.")>] offset : int64 option;
84125
}
85126
@@ -94,18 +135,22 @@ VB.Net:
94135

95136
```VB.NET
96137
Class Options
97-
<CommandLine.Option("r", "read", Required:=True, HelpText:="Input files to be processed.")>
98-
Public Property InputFiles As IEnumerable(Of String)
99-
100-
' Omitting long name, defaults to name of property, ie "--verbose"
101-
<CommandLine.Option(HelpText:="Prints all messages to standard output.")>
102-
Public Property Verbose As Boolean
103-
104-
<CommandLine.Option([Default]:="中文", HelpText:="Content language.")>
105-
Public Property Language As String
106-
107-
<CommandLine.Value(0, MetaName:="offset", HelpText:="File offset.")>
108-
Public Property Offset As Long?
138+
<CommandLine.Option('r', "read", Required := true,
139+
HelpText:="Input files to be processed.")>
140+
Public Property InputFiles As IEnumerable(Of String)
141+
142+
' Omitting long name, defaults to name of property, ie "--verbose"
143+
<CommandLine.Option(
144+
HelpText:="Prints all messages to standard output.")>
145+
Public Property Verbose As Boolean
146+
147+
<CommandLine.Option(Default:="中文",
148+
HelpText:="Content language.")>
149+
Public Property Language As String
150+
151+
<CommandLine.Value(0, MetaName:="offset",
152+
HelpText:="File offset.")>
153+
Public Property Offset As Long?
109154
End Class
110155

111156
Sub Main(ByVal args As String())

src/CommandLine/Core/TypeConverter.cs

+15-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ private static Maybe<object> ChangeTypeScalar(string value, Type conversionType,
4949
return result.ToMaybe();
5050
}
5151

52+
private static object ConvertString(string value, Type type, CultureInfo conversionCulture)
53+
{
54+
try
55+
{
56+
return Convert.ChangeType(value, type, conversionCulture);
57+
}
58+
catch (InvalidCastException)
59+
{
60+
// Required for converting from string to TimeSpan because Convert.ChangeType can't
61+
return System.ComponentModel.TypeDescriptor.GetConverter(type).ConvertFrom(null, conversionCulture, value);
62+
}
63+
}
64+
5265
private static Result<object, Exception> ChangeTypeScalarImpl(string value, Type conversionType, CultureInfo conversionCulture, bool ignoreValueCase)
5366
{
5467
Func<object> changeType = () =>
@@ -71,10 +84,9 @@ private static Result<object, Exception> ChangeTypeScalarImpl(string value, Type
7184
() =>
7285
#if !SKIP_FSHARP
7386
isFsOption
74-
? FSharpOptionHelper.Some(type, Convert.ChangeType(value, type, conversionCulture)) :
87+
? FSharpOptionHelper.Some(type, ConvertString(value, type, conversionCulture)) :
7588
#endif
76-
Convert.ChangeType(value, type, conversionCulture);
77-
89+
ConvertString(value, type, conversionCulture);
7890
#if !SKIP_FSHARP
7991
Func<object> empty = () => isFsOption ? FSharpOptionHelper.None(type) : null;
8092
#else

src/CommandLine/UnParserExtensions.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class UnParserSettings
1818
private bool preferShortName;
1919
private bool groupSwitches;
2020
private bool useEqualToken;
21+
private bool showHidden;
2122

2223
/// <summary>
2324
/// Gets or sets a value indicating whether unparsing process shall prefer short or long names.
@@ -46,6 +47,14 @@ public bool UseEqualToken
4647
set { PopsicleSetter.Set(Consumed, ref useEqualToken, value); }
4748
}
4849

50+
/// <summary>
51+
/// Gets or sets a value indicating whether unparsing process shall expose hidden options.
52+
/// </summary>
53+
public bool ShowHidden
54+
{
55+
get { return showHidden; }
56+
set { PopsicleSetter.Set(Consumed, ref showHidden, value); }
57+
}
4958
/// <summary>
5059
/// Factory method that creates an instance of <see cref="CommandLine.UnParserSettings"/> with GroupSwitches set to true.
5160
/// </summary>
@@ -119,6 +128,7 @@ public static string FormatCommandLine<T>(this Parser parser, T options, Action<
119128
var allOptSpecs = from info in specs.Where(i => i.Specification.Tag == SpecificationType.Option)
120129
let o = (OptionSpecification)info.Specification
121130
where o.TargetType != TargetType.Switch || (o.TargetType == TargetType.Switch && ((bool)info.Value))
131+
where !o.Hidden || settings.ShowHidden
122132
orderby o.UniqueName()
123133
select info;
124134

@@ -206,9 +216,10 @@ private static string FormatOption(OptionSpecification spec, object value, UnPar
206216

207217
private static string FormatName(this OptionSpecification optionSpec, UnParserSettings settings)
208218
{
209-
var longName =
210-
optionSpec.LongName.Length > 0
211-
&& !settings.PreferShortName;
219+
// Have a long name and short name not preferred? Go with long!
220+
// No short name? Has to be long!
221+
var longName = (optionSpec.LongName.Length > 0 && !settings.PreferShortName)
222+
|| optionSpec.ShortName.Length == 0;
212223

213224
return
214225
new StringBuilder(longName

tests/CommandLine.Tests/CommandLine.Tests.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
<Link>Properties\SharedAssemblyInfo.cs</Link>
5959
</Compile>
6060
<Compile Include="CultureInfoExtensions.cs" />
61+
<Compile Include="Fakes\Hidden_Option.cs" />
6162
<Compile Include="Fakes\Options_With_Default_Set_To_Sequence.cs" />
6263
<Compile Include="Fakes\Options_With_Guid.cs" />
6364
<Compile Include="Fakes\Options_With_Option_And_Value_Of_String_Type.cs" />
@@ -95,6 +96,7 @@
9596
<Compile Include="Fakes\Options_With_Two_Options_Having_Required_Set_To_True.cs" />
9697
<Compile Include="Fakes\Options_With_Required_Set_To_True.cs" />
9798
<Compile Include="Fakes\Options_With_Required_Set_To_True_Within_Same_Set.cs" />
99+
<Compile Include="Fakes\Options_With_TimeSpan.cs" />
98100
<Compile Include="Fakes\Help_Fakes.cs" />
99101
<Compile Include="Fakes\IInterface_With_Two_Scalar_Options.cs" />
100102
<Compile Include="Fakes\Immutable_Verb_Fakes.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace CommandLine.Tests.Fakes
8+
{
9+
public class Hidden_Option
10+
{
11+
[Option('h', "hiddenOption", Default="hidden", Hidden = true)]
12+
public string HiddenOption { get; set; }
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
2+
3+
using System;
4+
5+
namespace CommandLine.Tests.Fakes
6+
{
7+
public class Options_With_TimeSpan
8+
{
9+
[Option('d', "duration")]
10+
public TimeSpan Duration { get; set; }
11+
}
12+
}

tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs

+16
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,22 @@ public void Parse_Guid(string[] arguments, Options_With_Guid expected)
10231023
// Teardown
10241024
}
10251025

1026+
[Fact]
1027+
public void Parse_TimeSpan()
1028+
{
1029+
// Fixture setup
1030+
var expectedResult = new Options_With_TimeSpan { Duration = TimeSpan.FromMinutes(42) };
1031+
1032+
// Exercize system
1033+
var result = InvokeBuild<Options_With_TimeSpan>(
1034+
new[] { "--duration=00:42:00" });
1035+
1036+
// Verify outcome
1037+
expectedResult.ShouldBeEquivalentTo(((Parsed<Options_With_TimeSpan>)result).Value);
1038+
1039+
// Teardown
1040+
}
1041+
10261042
public static IEnumerable<object> RequiredValueStringData
10271043
{
10281044
get

tests/CommandLine.Tests/Unit/UnParserExtensionsTests.cs

+17
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ public static void UnParsing_immutable_instance_returns_command_line(Immutable_S
4040
.ShouldBeEquivalentTo(result);
4141
}
4242

43+
[Theory]
44+
[MemberData("UnParseDataHidden")]
45+
public static void Unparsing_hidden_option_returns_command_line(Hidden_Option options, bool showHidden, string result)
46+
{
47+
new Parser()
48+
.FormatCommandLine(options, config => config.ShowHidden = showHidden)
49+
.ShouldBeEquivalentTo(result);
50+
}
51+
4352
#if !SKIP_FSHARP
4453
[Theory]
4554
[MemberData("UnParseDataFSharpOption")]
@@ -141,6 +150,14 @@ public static IEnumerable<object> UnParseDataImmutable
141150
}
142151
}
143152

153+
public static IEnumerable<object> UnParseDataHidden
154+
{
155+
get
156+
{
157+
yield return new object[] { new Hidden_Option { HiddenOption = "hidden" }, true, "--hiddenOption hidden" };
158+
yield return new object[] { new Hidden_Option { HiddenOption = "hidden" }, false, ""};
159+
}
160+
}
144161
#if !SKIP_FSHARP
145162
public static IEnumerable<object> UnParseDataFSharpOption
146163
{

0 commit comments

Comments
 (0)