Skip to content

Commit 6cc36dc

Browse files
committed
added initial prototype of the fluent builder
1 parent a1108f4 commit 6cc36dc

File tree

7 files changed

+419
-0
lines changed

7 files changed

+419
-0
lines changed

FluentCommandLineParser.Tests/FluentCommandLineParser.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
</ItemGroup>
7777
<ItemGroup>
7878
<Compile Include="CommandLineOptionFormatterTests.cs" />
79+
<Compile Include="FluentCommandLineParserBuilderTests.cs" />
7980
<Compile Include="FluentCommandLineParserTests.cs">
8081
<SubType>Code</SubType>
8182
</Compile>
@@ -107,6 +108,7 @@
107108
<Compile Include="Internals\TestContextBase.cs" />
108109
<Compile Include="Internals\Validators\OptionNameValidatorTests.cs" />
109110
<Compile Include="Internals\Validators\NoDuplicateOptionValidatorTests.cs" />
111+
<Compile Include="TestApplicationArgs.cs" />
110112
<Compile Include="TestContext\TestContext.cs" />
111113
<Compile Include="FluentCommandLineParser\TestContext\TestType.cs" />
112114
<Compile Include="FluentCommandLineParser\when_executing_parse_operation\with_options_that_have_not_been_setup.cs" />
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#region License
2+
// FluentCommandLineParserBuilderTests.cs
3+
// Copyright (c) 2013, Simon Williams
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without modification, are permitted provide
7+
// d that the following conditions are met:
8+
//
9+
// Redistributions of source code must retain the above copyright notice, this list of conditions and the
10+
// following disclaimer.
11+
//
12+
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
13+
// the following disclaimer in the documentation and/or other materials provided with the distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
16+
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17+
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19+
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22+
// POSSIBILITY OF SUCH DAMAGE.
23+
#endregion
24+
25+
using Fclp.Tests.Internals;
26+
using Machine.Specifications;
27+
28+
namespace Fclp.Tests
29+
{
30+
public class FluentCommandLineParserBuilderTests
31+
{
32+
[Subject(typeof(FluentCommandLineBuilder<>))]
33+
abstract class FluentCommandLineParserBuilderTestContext : TestContextBase<FluentCommandLineBuilder<TestApplicationArgs>>
34+
{
35+
Establish context = () => CreateSut();
36+
}
37+
38+
sealed class Parse
39+
{
40+
abstract class ParseTestContext : FluentCommandLineParserBuilderTestContext
41+
{
42+
protected static string[] args;
43+
protected static ICommandLineParserResult result;
44+
45+
Because of = () =>
46+
result = sut.Parse(args);
47+
}
48+
49+
class when_invoked_with_example : ParseTestContext
50+
{
51+
Establish context = () =>
52+
{
53+
sut.Setup(x => x.NewValue)
54+
.As('v', "value");
55+
56+
sut.Setup(x => x.RecordId)
57+
.As('r', "recordId");
58+
59+
sut.Setup(x => x.Silent)
60+
.As('s', "silent");
61+
62+
args = new[] { "-r", "10", "-v", "Mr. Smith", "--silent" };
63+
};
64+
65+
It should_enable_silent = () =>
66+
sut.Object.Silent.ShouldBeTrue();
67+
68+
It should_assign_the_record_id = () =>
69+
sut.Object.RecordId.ShouldEqual(10);
70+
71+
It should_assign_the_new_value = () =>
72+
sut.Object.NewValue.ShouldEqual("Mr. Smith");
73+
}
74+
75+
class when_required_option_is_not_provided : ParseTestContext
76+
{
77+
Establish context = () =>
78+
{
79+
sut.Setup(x => x.NewValue)
80+
.As('v', "value")
81+
.Required();
82+
83+
args = new[] { "-r", "10", "--silent" };
84+
};
85+
86+
It should_report_an_error = () =>
87+
result.HasErrors.ShouldBeTrue();
88+
}
89+
90+
class when_default_is_specified_on_an_option_that_is_not_specified : ParseTestContext
91+
{
92+
protected static string expectedDefaultValue;
93+
94+
Establish context = () =>
95+
{
96+
Create(out expectedDefaultValue);
97+
98+
sut.Setup(x => x.RecordId)
99+
.As('r', "recordId");
100+
101+
sut.Setup(x => x.Silent)
102+
.As('s', "silent");
103+
104+
sut.Setup(x => x.NewValue)
105+
.As('v', "value")
106+
.SetDefault(expectedDefaultValue);
107+
108+
args = new[] { "-r", "10", "--silent" };
109+
};
110+
111+
It should_assign_the_specified_default_as_the_new_value = () =>
112+
sut.Object.NewValue.ShouldEqual(expectedDefaultValue);
113+
114+
}
115+
}
116+
}
117+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#region License
2+
// TestApplicationArgs.cs
3+
// Copyright (c) 2013, Simon Williams
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without modification, are permitted provide
7+
// d that the following conditions are met:
8+
//
9+
// Redistributions of source code must retain the above copyright notice, this list of conditions and the
10+
// following disclaimer.
11+
//
12+
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
13+
// the following disclaimer in the documentation and/or other materials provided with the distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
16+
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17+
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19+
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22+
// POSSIBILITY OF SUCH DAMAGE.
23+
#endregion
24+
namespace Fclp.Tests
25+
{
26+
/// <summary>
27+
///
28+
/// </summary>
29+
public class TestApplicationArgs
30+
{
31+
/// <summary>
32+
/// Gets or sets the record id.
33+
/// </summary>
34+
public int RecordId { get; set; }
35+
36+
/// <summary>
37+
/// Gets or sets a value indicating whether this <see cref="ApplicationArgs"/> is silent.
38+
/// </summary>
39+
public bool Silent { get; set; }
40+
41+
/// <summary>
42+
/// Gets or sets the new value.
43+
/// </summary>
44+
public string NewValue { get; set; }
45+
}
46+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#region License
2+
// FluentCommandLineBuilder.cs
3+
// Copyright (c) 2013, Simon Williams
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without modification, are permitted provide
7+
// d that the following conditions are met:
8+
//
9+
// Redistributions of source code must retain the above copyright notice, this list of conditions and the
10+
// following disclaimer.
11+
//
12+
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
13+
// the following disclaimer in the documentation and/or other materials provided with the distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
16+
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17+
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19+
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22+
// POSSIBILITY OF SUCH DAMAGE.
23+
#endregion
24+
25+
using System;
26+
using System.Linq.Expressions;
27+
using Fclp.Internals;
28+
29+
namespace Fclp
30+
{
31+
/// <summary>
32+
/// Prototype parser that constructs and populates the specified type of object from command line arguments.
33+
/// </summary>
34+
public class FluentCommandLineBuilder<TBuildType> where TBuildType : new()
35+
{
36+
private readonly FluentCommandLineParser _parser;
37+
38+
/// <summary>
39+
/// Gets the constructed object.
40+
/// </summary>
41+
public TBuildType Object { get; private set; }
42+
43+
/// <summary>
44+
/// Initialises a new instance of the <see cref="FluentCommandLineBuilder{TBuildType}"/> class.
45+
/// </summary>
46+
public FluentCommandLineBuilder()
47+
{
48+
Object = new TBuildType();
49+
_parser = new FluentCommandLineParser();
50+
}
51+
52+
/// <summary>
53+
/// Sets up an Option for a write-able property on the type being built.
54+
/// </summary>
55+
public ICommandLineOptionBuilderFluent<TProperty> Setup<TProperty>(Expression<Func<TBuildType, TProperty>> propertyPicker)
56+
{
57+
return new CommandLineOptionBuilderFluent<TBuildType, TProperty>(_parser, Object, propertyPicker);
58+
}
59+
60+
/// <summary>
61+
/// Parses the specified <see><cref>T:System.String[]</cref></see> using the setup Options.
62+
/// </summary>
63+
/// <param name="args">The <see><cref>T:System.String[]</cref></see> to parse.</param>
64+
/// <returns>An <see cref="ICommandLineParserResult"/> representing the results of the parse operation.</returns>
65+
public ICommandLineParserResult Parse(string[] args)
66+
{
67+
return _parser.Parse(args);
68+
}
69+
}
70+
}

FluentCommandLineParser/FluentCommandLineParser.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@
5555
</ItemGroup>
5656
<ItemGroup>
5757
<Compile Include="CommandLineParserErrorFormatter.cs" />
58+
<Compile Include="FluentCommandLineBuilder.cs" />
59+
<Compile Include="ICommandLineOptionBuilderFluent.cs" />
5860
<Compile Include="ICommandLineParserErrorFormatter.cs" />
5961
<Compile Include="IHelpCommandLineOptionFluent.cs" />
62+
<Compile Include="Internals\CommandLineOptionBuilderFluent.cs" />
6063
<Compile Include="Internals\CommandLineParserEngineMark2.cs" />
6164
<Compile Include="Internals\EmptyHelpCommandLineOption.cs" />
6265
<Compile Include="Internals\Errors\OptionSyntaxParseError.cs" />
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#region License
2+
// ICommandLineOptionBuilderFluent.cs
3+
// Copyright (c) 2013, Simon Williams
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without modification, are permitted provide
7+
// d that the following conditions are met:
8+
//
9+
// Redistributions of source code must retain the above copyright notice, this list of conditions and the
10+
// following disclaimer.
11+
//
12+
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
13+
// the following disclaimer in the documentation and/or other materials provided with the distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
16+
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17+
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19+
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22+
// POSSIBILITY OF SUCH DAMAGE.
23+
#endregion
24+
namespace Fclp
25+
{
26+
/// <summary>
27+
/// Defines the fluent interface for setting up a <see cref="ICommandLineOptionFluent{TProperty}"/>.
28+
/// </summary>
29+
public interface ICommandLineOptionBuilderFluent<TProperty>
30+
{
31+
/// <summary>
32+
/// Setup a new <see cref="ICommandLineOptionFluent{T}"/> using the specified short and long Option name.
33+
/// </summary>
34+
/// <param name="shortOption">The short name for the Option. This must not be <c>whitespace</c> or a control character.</param>
35+
/// <param name="longOption">The long name for the Option. This must not be <c>null</c>, <c>empty</c> or only <c>whitespace</c>.</param>
36+
/// <returns></returns>
37+
/// <exception cref="OptionAlreadyExistsException">
38+
/// A Option with the same <paramref name="shortOption"/> name or <paramref name="longOption"/> name already exists in the <see cref="IFluentCommandLineParser"/>.
39+
/// </exception>
40+
/// <exception cref="InvalidOptionNameException">
41+
/// Either <paramref name="shortOption"/> or <paramref name="longOption"/> are not valid. <paramref name="shortOption"/> must not be <c>whitespace</c>
42+
/// or a control character. <paramref name="longOption"/> must not be <c>null</c>, <c>empty</c> or only <c>whitespace</c>.
43+
/// </exception>
44+
ICommandLineOptionFluent<TProperty> As(char shortOption, string longOption);
45+
46+
/// <summary>
47+
/// Setup a new <see cref="ICommandLineOptionFluent{T}"/> using the specified short Option name.
48+
/// </summary>
49+
/// <param name="shortOption">The short name for the Option. This must not be <c>whitespace</c> or a control character.</param>
50+
/// <returns></returns>
51+
/// <exception cref="InvalidOptionNameException">if <paramref name="shortOption"/> is invalid for a short option.</exception>
52+
/// <exception cref="OptionAlreadyExistsException">
53+
/// A Option with the same <paramref name="shortOption"/> name
54+
/// already exists in the <see cref="IFluentCommandLineParser"/>.
55+
/// </exception>
56+
ICommandLineOptionFluent<TProperty> As(char shortOption);
57+
58+
/// <summary>
59+
/// Setup a new <see cref="ICommandLineOptionFluent{T}"/> using the specified long Option name.
60+
/// </summary>
61+
/// <param name="longOption">The long name for the Option. This must not be <c>null</c>, <c>empty</c> or only <c>whitespace</c>.</param>
62+
/// <exception cref="InvalidOptionNameException">if <paramref name="longOption"/> is invalid for a long option.</exception>
63+
/// <exception cref="OptionAlreadyExistsException">
64+
/// A Option with the same <paramref name="longOption"/> name already exists in the <see cref="IFluentCommandLineParser"/>.
65+
/// </exception>
66+
ICommandLineOptionFluent<TProperty> As(string longOption);
67+
}
68+
}

0 commit comments

Comments
 (0)