Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 61 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,43 @@ You can utilize the parser library in several ways:
1. Create a class to define valid options, and to receive the parsed options.
2. Call ParseArguments with the args string array.

C# Quick Start:

```csharp
using System;
using CommandLine;

namespace QuickStart
{
class Program
{
public class Options
{
[Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")]
public bool Verbose { get; set; }
}

static void Main(string[] args)
{
Parser.Default.ParseArguments<Options>(args)
.WithParsed<Options>(o =>
{
if (o.Verbose)
{
Console.WriteLine($"Verbose output enabled. Current Arguments: -v {o.Verbose}");
Console.WriteLine("Quick Start Example! App is in Verbose mode!");
}
else
{
Console.WriteLine($"Current Arguments: -v {o.Verbose}");
Console.WriteLine("Quick Start Example!");
}
});
}
}
}
```

C# Examples:

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

// Omitting long name, defaults to name of property, ie "--verbose"
[Option(Default = false, HelpText = "Prints all messages to standard output.")]
[Option(
Default = false,
HelpText = "Prints all messages to standard output.")]
public bool Verbose { get; set; }

[Option("stdin", Default = false, HelpText = "Read from stdin")]

[Option("stdin",
Default = false
HelpText = "Read from stdin")]
public bool stdin { get; set; }

[Value(0, MetaName = "offset", HelpText = "File offset.")]
Expand All @@ -79,7 +120,7 @@ F# Examples:
type options = {
[<Option('r', "read", Required = true, HelpText = "Input files.")>] files : seq<string>;
[<Option(HelpText = "Prints all messages to standard output.")>] verbose : bool;
[<Option(DefaultValue = "русский", HelpText = "Content language.")>] language : string;
[<Option(Default = "русский", HelpText = "Content language.")>] language : string;
[<Value(0, MetaName="offset", HelpText = "File offset.")>] offset : int64 option;
}

Expand All @@ -94,18 +135,22 @@ VB.Net:

```VB.NET
Class Options
<CommandLine.Option("r", "read", Required:=True, HelpText:="Input files to be processed.")>
Public Property InputFiles As IEnumerable(Of String)

' Omitting long name, defaults to name of property, ie "--verbose"
<CommandLine.Option(HelpText:="Prints all messages to standard output.")>
Public Property Verbose As Boolean

<CommandLine.Option([Default]:="中文", HelpText:="Content language.")>
Public Property Language As String

<CommandLine.Value(0, MetaName:="offset", HelpText:="File offset.")>
Public Property Offset As Long?
<CommandLine.Option('r', "read", Required := true,
HelpText:="Input files to be processed.")>
Public Property InputFiles As IEnumerable(Of String)

' Omitting long name, defaults to name of property, ie "--verbose"
<CommandLine.Option(
HelpText:="Prints all messages to standard output.")>
Public Property Verbose As Boolean

<CommandLine.Option(Default:="中文",
HelpText:="Content language.")>
Public Property Language As String

<CommandLine.Value(0, MetaName:="offset",
HelpText:="File offset.")>
Public Property Offset As Long?
End Class

Sub Main(ByVal args As String())
Expand Down
18 changes: 15 additions & 3 deletions src/CommandLine/Core/TypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ private static Maybe<object> ChangeTypeScalar(string value, Type conversionType,
return result.ToMaybe();
}

private static object ConvertString(string value, Type type, CultureInfo conversionCulture)
{
try
{
return Convert.ChangeType(value, type, conversionCulture);
}
catch (InvalidCastException)
{
// Required for converting from string to TimeSpan because Convert.ChangeType can't
return System.ComponentModel.TypeDescriptor.GetConverter(type).ConvertFrom(null, conversionCulture, value);
}
}

private static Result<object, Exception> ChangeTypeScalarImpl(string value, Type conversionType, CultureInfo conversionCulture, bool ignoreValueCase)
{
Func<object> changeType = () =>
Expand All @@ -71,10 +84,9 @@ private static Result<object, Exception> ChangeTypeScalarImpl(string value, Type
() =>
#if !SKIP_FSHARP
isFsOption
? FSharpOptionHelper.Some(type, Convert.ChangeType(value, type, conversionCulture)) :
? FSharpOptionHelper.Some(type, ConvertString(value, type, conversionCulture)) :
#endif
Convert.ChangeType(value, type, conversionCulture);

ConvertString(value, type, conversionCulture);
#if !SKIP_FSHARP
Func<object> empty = () => isFsOption ? FSharpOptionHelper.None(type) : null;
#else
Expand Down
17 changes: 14 additions & 3 deletions src/CommandLine/UnParserExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class UnParserSettings
private bool preferShortName;
private bool groupSwitches;
private bool useEqualToken;
private bool showHidden;

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

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

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

private static string FormatName(this OptionSpecification optionSpec, UnParserSettings settings)
{
var longName =
optionSpec.LongName.Length > 0
&& !settings.PreferShortName;
// Have a long name and short name not preferred? Go with long!
// No short name? Has to be long!
var longName = (optionSpec.LongName.Length > 0 && !settings.PreferShortName)
|| optionSpec.ShortName.Length == 0;

return
new StringBuilder(longName
Expand Down
2 changes: 2 additions & 0 deletions tests/CommandLine.Tests/CommandLine.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="CultureInfoExtensions.cs" />
<Compile Include="Fakes\Hidden_Option.cs" />
<Compile Include="Fakes\Options_With_Default_Set_To_Sequence.cs" />
<Compile Include="Fakes\Options_With_Guid.cs" />
<Compile Include="Fakes\Options_With_Option_And_Value_Of_String_Type.cs" />
Expand Down Expand Up @@ -95,6 +96,7 @@
<Compile Include="Fakes\Options_With_Two_Options_Having_Required_Set_To_True.cs" />
<Compile Include="Fakes\Options_With_Required_Set_To_True.cs" />
<Compile Include="Fakes\Options_With_Required_Set_To_True_Within_Same_Set.cs" />
<Compile Include="Fakes\Options_With_TimeSpan.cs" />
<Compile Include="Fakes\Help_Fakes.cs" />
<Compile Include="Fakes\IInterface_With_Two_Scalar_Options.cs" />
<Compile Include="Fakes\Immutable_Verb_Fakes.cs" />
Expand Down
14 changes: 14 additions & 0 deletions tests/CommandLine.Tests/Fakes/Hidden_Option.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CommandLine.Tests.Fakes
{
public class Hidden_Option
{
[Option('h', "hiddenOption", Default="hidden", Hidden = true)]
public string HiddenOption { get; set; }
}
}
12 changes: 12 additions & 0 deletions tests/CommandLine.Tests/Fakes/Options_With_TimeSpan.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.

using System;

namespace CommandLine.Tests.Fakes
{
public class Options_With_TimeSpan
{
[Option('d', "duration")]
public TimeSpan Duration { get; set; }
}
}
16 changes: 16 additions & 0 deletions tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,22 @@ public void Parse_Guid(string[] arguments, Options_With_Guid expected)
// Teardown
}

[Fact]
public void Parse_TimeSpan()
{
// Fixture setup
var expectedResult = new Options_With_TimeSpan { Duration = TimeSpan.FromMinutes(42) };

// Exercize system
var result = InvokeBuild<Options_With_TimeSpan>(
new[] { "--duration=00:42:00" });

// Verify outcome
expectedResult.ShouldBeEquivalentTo(((Parsed<Options_With_TimeSpan>)result).Value);

// Teardown
}

public static IEnumerable<object> RequiredValueStringData
{
get
Expand Down
17 changes: 17 additions & 0 deletions tests/CommandLine.Tests/Unit/UnParserExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ public static void UnParsing_immutable_instance_returns_command_line(Immutable_S
.ShouldBeEquivalentTo(result);
}

[Theory]
[MemberData("UnParseDataHidden")]
public static void Unparsing_hidden_option_returns_command_line(Hidden_Option options, bool showHidden, string result)
{
new Parser()
.FormatCommandLine(options, config => config.ShowHidden = showHidden)
.ShouldBeEquivalentTo(result);
}

#if !SKIP_FSHARP
[Theory]
[MemberData("UnParseDataFSharpOption")]
Expand Down Expand Up @@ -141,6 +150,14 @@ public static IEnumerable<object> UnParseDataImmutable
}
}

public static IEnumerable<object> UnParseDataHidden
{
get
{
yield return new object[] { new Hidden_Option { HiddenOption = "hidden" }, true, "--hiddenOption hidden" };
yield return new object[] { new Hidden_Option { HiddenOption = "hidden" }, false, ""};
}
}
#if !SKIP_FSHARP
public static IEnumerable<object> UnParseDataFSharpOption
{
Expand Down