Permalink
Browse files

[Separator]

  • Loading branch information...
1 parent 75cfa1f commit 269cb04a9406d7bb97d788ef6fd17610de135946 @adrianaisemberg committed Apr 5, 2012
Showing with 255 additions and 19 deletions.
  1. +1 −0 CLAP/CLAP.csproj
  2. +45 −0 CLAP/Exceptions.cs
  3. +7 −4 CLAP/ParserRegistration.cs
  4. +29 −1 CLAP/ParserRunner.cs
  5. +2 −2 CLAP/Properties/AssemblyInfo.cs
  6. +6 −1 CLAP/Utils.cs
  7. +18 −11 CLAP/ValuesFactory.cs
  8. +77 −0 Tests/Samples.cs
  9. +70 −0 Tests/Tests.cs
View
1 CLAP/CLAP.csproj
@@ -86,6 +86,7 @@
<Compile Include="DefaultProvider.cs" />
<Compile Include="HelpInfo.cs" />
<Compile Include="Interception\UserVerbExecutionContext.cs" />
+ <Compile Include="Pair.cs" />
<Compile Include="Parser.WinForms.cs" />
<Compile Include="EnvironmentParserHandlers.cs" />
<Compile Include="Parser.Console.cs" />
View
45 CLAP/Exceptions.cs
@@ -437,4 +437,49 @@ public DuplicateGlobalHandlerException(string name)
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
+
+ [Serializable]
+ public class NonArrayParameterWithSeparatorException : CommandLineParserException
+ {
+ /// <summary>
+ /// The parameter
+ /// </summary>
+ public ParameterInfo Parameter { get; private set; }
+
+ public NonArrayParameterWithSeparatorException(ParameterInfo parameter)
+ : base("Parameter '{0}' of '{1}' is marked with [{2}] but it is not an array".FormatWith(
+ parameter.Name,
+ parameter.Member.Name,
+ typeof(SeparatorAttribute).Name))
+ {
+ Parameter = parameter;
+ }
+
+ protected NonArrayParameterWithSeparatorException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context)
+ : base(info, context) { }
+ }
+
+ [Serializable]
+ public class InvalidSeparatorException : CommandLineParserException
+ {
+ /// <summary>
+ /// The parameter
+ /// </summary>
+ public ParameterInfo Parameter { get; private set; }
+
+ public InvalidSeparatorException(ParameterInfo parameter)
+ : base("Parameter '{0}' of '{1}' has an invalid separator. A separator cannot be empty or contain spaces.".FormatWith(
+ parameter.Name,
+ parameter.Member.Name))
+ {
+ Parameter = parameter;
+ }
+
+ protected InvalidSeparatorException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context)
+ : base(info, context) { }
+ }
}
View
11 CLAP/ParserRegistration.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using CLAP.Interception;
+using System.Reflection;
namespace CLAP
{
@@ -26,13 +26,16 @@ public sealed class ParserRegistration
internal Action<PostVerbExecutionContext> RegisteredPostVerbInterceptor { get; private set; }
internal Func<string> HelpGetter { get; private set; }
- internal Func<Type, string, string, object> ParameterValueGetter { get; private set; }
+ internal Func<ParameterInfo, Type, string, string, object> ParameterValueGetter { get; private set; }
#endregion Properties
#region Constructors
- internal ParserRegistration(Type[] types, Func<string> helpGetter, Func<Type, string, string, object> parameterValueGetter)
+ internal ParserRegistration(
+ Type[] types,
+ Func<string> helpGetter,
+ Func<ParameterInfo, Type, string, string, object> parameterValueGetter)
{
m_types = types;
@@ -249,7 +252,7 @@ private void RegisterParameterHandlerInternal<TParameter>(string names, Action<T
}
else
{
- v = ParameterValueGetter(typeof(TParameter), string.Empty, str);
+ v = ParameterValueGetter(null, typeof(TParameter), string.Empty, str);
}
action((TParameter)v);
View
30 CLAP/ParserRunner.cs
@@ -366,6 +366,10 @@ internal static void Validate(Type type, ParserRegistration registration)
//
ValidateParameterDefaults(verbMethods);
+ // [Separator] can be applied only to array parameters
+ //
+ ValidateSeparators(verbMethods);
+
// no duplicate globals
//
ValidateDuplicateGlobals(type, registration);
@@ -426,6 +430,30 @@ private static void ValidateParameterDefaults(IEnumerable<Method> verbs)
}
}
+ private static void ValidateSeparators(IEnumerable<Method> verbs)
+ {
+ var parameters = verbs.SelectMany(v => v.MethodInfo.GetParameters()).ToList();
+
+ var nonArrayWithSeparator = parameters.Where(p => !p.ParameterType.IsArray && p.HasAttribute<SeparatorAttribute>());
+
+ if (nonArrayWithSeparator.Any())
+ {
+ throw new NonArrayParameterWithSeparatorException(nonArrayWithSeparator.First());
+ }
+
+ var separators = parameters.
+ Where(p => p.HasAttribute<SeparatorAttribute>()).
+ Select(p => Pair.Create(p, p.GetAttribute<SeparatorAttribute>().Separator));
+
+ var invalidSeparator = separators.
+ FirstOrDefault(pair => string.IsNullOrEmpty(pair.Second) || pair.Second.Contains(" "));
+
+ if (invalidSeparator != null)
+ {
+ throw new InvalidSeparatorException(invalidSeparator.First);
+ }
+ }
+
private static void ValidateDefinedEmptyHandlers(Type type)
{
var definedEmptyHandlers = type.GetMethodsWith<EmptyAttribute>();
@@ -691,7 +719,7 @@ private void HandleDefinedGlobals(Dictionary<string, string> args, object obj)
{
var p = parameters.First();
- var value = ValuesFactory.GetValueForParameter(p.ParameterType, key, stringValue);
+ var value = ValuesFactory.GetValueForParameter(p, p.ParameterType, key, stringValue);
// validation
//
View
4 CLAP/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("3.9.1.0")]
-[assembly: AssemblyFileVersion("3.9.1.0")]
+[assembly: AssemblyVersion("4.0")]
+[assembly: AssemblyFileVersion("4.0")]
View
7 CLAP/Utils.cs
@@ -109,9 +109,14 @@ public static string StringJoin(this IEnumerable<string> strings, string separat
return string.Join(separator, strings.ToArray());
}
+ public static IEnumerable<string> SplitBy(this string str, string separator)
+ {
+ return str.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
public static IEnumerable<string> CommaSplit(this string str)
{
- return str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ return SplitBy(str, ",");
}
public static void Each<T>(this IEnumerable<T> collection, Action<T, int> action)
View
29 CLAP/ValuesFactory.cs
@@ -12,7 +12,11 @@ namespace CLAP
{
internal static class ValuesFactory
{
- internal static object GetValueForParameter(Type parameterType, string inputKey, string stringValue)
+ internal static object GetValueForParameter(
+ ParameterInfo parameter,
+ Type parameterType,
+ string inputKey,
+ string stringValue)
{
// a string doesn't need convertion
//
@@ -45,7 +49,7 @@ internal static object GetValueForParameter(Type parameterType, string inputKey,
{
// if can't deserialize - try converting it
//
- return ConvertParameterValue(inputKey, stringValue, parameterType);
+ return ConvertParameterValue(inputKey, stringValue, parameter, parameterType, null);
}
}
catch (ValidationException)
@@ -58,21 +62,17 @@ internal static object GetValueForParameter(Type parameterType, string inputKey,
{
// tried deserialize but failed - try converting
//
- return ConvertParameterValue(inputKey, stringValue, parameterType, ex);
+ return ConvertParameterValue(inputKey, stringValue, parameter, parameterType, ex);
}
}
throw new MissingArgumentValueException(inputKey);
}
- private static object ConvertParameterValue(string inputKey, string stringValue, Type parameterType)
- {
- return ConvertParameterValue(inputKey, stringValue, parameterType, null);
- }
-
private static object ConvertParameterValue(
string inputKey,
string stringValue,
+ ParameterInfo parameter,
Type parameterType,
Exception deserializationException)
{
@@ -81,7 +81,14 @@ private static object ConvertParameterValue(string inputKey, string stringValue,
// if array
if (parameterType.IsArray)
{
- var stringValues = stringValue.CommaSplit();
+ var separator = ",";
+
+ if (parameter != null && parameter.HasAttribute<SeparatorAttribute>())
+ {
+ separator = parameter.GetAttribute<SeparatorAttribute>().Separator;
+ }
+
+ var stringValues = stringValue.SplitBy(separator);
// The type of the array element
//
@@ -210,7 +217,7 @@ private static TConvert[] ConvertToArray<TConvert>(string[] values)
//
if (value is string && !(parameterInfo.ParameterType == typeof(string)))
{
- value = GetValueForParameter(parameterInfo.ParameterType, "{DEFAULT}", (string)value);
+ value = GetValueForParameter(parameterInfo, parameterInfo.ParameterType, "{DEFAULT}", (string)value);
}
}
else
@@ -224,7 +231,7 @@ private static TConvert[] ConvertToArray<TConvert>(string[] values)
if (value == null && inputKey != null)
{
- value = GetValueForParameter(parameterInfo.ParameterType, inputKey, stringValue);
+ value = GetValueForParameter(parameterInfo, parameterInfo.ParameterType, inputKey, stringValue);
}
// validate each parameter
View
77 Tests/Samples.cs
@@ -10,6 +10,7 @@ namespace Tests
public interface IPrinter
{
void Print(String text);
+ void Reset();
}
public class Printer : IPrinter
@@ -20,6 +21,11 @@ public void Print(String text)
{
PrintedTexts.Add(text);
}
+
+ public void Reset()
+ {
+ PrintedTexts.Clear();
+ }
}
public class BaseSample
@@ -1382,4 +1388,75 @@ public class Sample_67
{
}
}
+
+ public class Sample_68
+ {
+ [Verb]
+ public static void Foo([Separator("|")] string x)
+ {
+ }
+ }
+
+ public class Sample_69 : BaseSample
+ {
+ [Verb]
+ public void Print([Separator("|")] String[] messages, String prefix)
+ {
+ if (messages == null)
+ {
+ return;
+ }
+
+ foreach (var msg in messages)
+ {
+ Printer.Print(prefix + msg);
+ }
+ }
+
+ [Verb]
+ public void PrintNumbers([Separator("-")] Int32[] numbers, String prefix)
+ {
+ if (numbers == null)
+ {
+ return;
+ }
+
+ foreach (var msg in numbers)
+ {
+ Printer.Print(prefix + msg);
+ }
+ }
+ }
+
+ public class Sample_70
+ {
+ [Verb]
+ public void Foo([Separator(" ")] Case[] enums)
+ {
+ }
+ }
+
+ public class Sample_71
+ {
+ [Verb]
+ public void Foo([Separator("a b")] Case[] enums)
+ {
+ }
+ }
+
+ public class Sample_72
+ {
+ [Verb]
+ public void Foo([Separator("")] Case[] enums)
+ {
+ }
+ }
+
+ public class Sample_73
+ {
+ [Verb]
+ public void Foo([Separator(null)] Case[] enums)
+ {
+ }
+ }
}
View
70 Tests/Tests.cs
@@ -381,6 +381,41 @@ public void Array_Strings()
}
[Test]
+ public void Array_Strings_WithSeparator()
+ {
+ var printer = new Printer();
+ var sample = new Sample_69 { Printer = printer };
+
+ // array
+ //
+ Parser.Run(new[]
+ {
+ "print",
+ "/messages:a|b|c",
+ "/prefix:test_",
+ }, sample);
+
+ Assert.AreEqual(3, printer.PrintedTexts.Count);
+ Assert.AreEqual("test_a", printer.PrintedTexts[0]);
+ Assert.AreEqual("test_b", printer.PrintedTexts[1]);
+ Assert.AreEqual("test_c", printer.PrintedTexts[2]);
+
+ sample.Printer.Reset();
+
+ Parser.Run(new[]
+ {
+ "printnumbers",
+ "/numbers:1-78-100",
+ "/prefix:test_",
+ }, sample);
+
+ Assert.AreEqual(3, printer.PrintedTexts.Count);
+ Assert.AreEqual("test_1", printer.PrintedTexts[0]);
+ Assert.AreEqual("test_78", printer.PrintedTexts[1]);
+ Assert.AreEqual("test_100", printer.PrintedTexts[2]);
+ }
+
+ [Test]
public void Array_Strings_NoInput()
{
var printer = new Printer();
@@ -2456,5 +2491,40 @@ public void ParametersWithSameAttributes_NoError()
{
Parser.Run<Sample_67>(new[] { "foo", "-x=a", "-y=b" });
}
+
+ [Test]
+ [ExpectedException(typeof(NonArrayParameterWithSeparatorException))]
+ public void NonArrayWithSeparator_Exception()
+ {
+ Parser.Run<Sample_68>(new[] { "foo", "-x=aaa" });
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidSeparatorException))]
+ public void NonArrayWithInvalidSeparator_Exception_1()
+ {
+ Parser.Run<Sample_70>(new[] { "foo", "-enums=aaa bbb ccc" });
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidSeparatorException))]
+ public void NonArrayWithInvalidSeparator_Exception_2()
+ {
+ Parser.Run<Sample_71>(new[] { "foo", "-enums=aaa bbb ccc" });
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidSeparatorException))]
+ public void NonArrayWithInvalidSeparator_Exception_3()
+ {
+ Parser.Run<Sample_72>(new[] { "foo", "-enums=aaa bbb ccc" });
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidSeparatorException))]
+ public void NonArrayWithInvalidSeparator_Exception_4()
+ {
+ Parser.Run<Sample_73>(new[] { "foo", "-enums=aaa bbb ccc" });
+ }
}
}

0 comments on commit 269cb04

Please sign in to comment.