/// <summary> /// Gets the instance of the created command object. /// </summary> /// <param name="tokens">Command line arguments to initialize command with.</param> /// <exception cref="Exception{OptionsValidationExceptionArgs}"> /// Indicates that at least one required option was not specified. /// </exception> internal object CreateInstance(IDictionary<string, OptionValue> tokens) { HashSet<string> availableOptions = new HashSet<string>(tokens.Select(t => t.Key.ToLowerInvariant())); OptionMetadata[] targetMetadata = null; // Find options set that matches our tokens collection. foreach (var usage in _metadata.Options) { HashSet<string> requiredOptions = new HashSet<string>(usage.Where(o => o.Required).Select(o => o.Name.ToLowerInvariant())); HashSet<string> allOptions = new HashSet<string>(usage.Select(o => o.Name.ToLowerInvariant())); if (requiredOptions.IsSubsetOf(availableOptions) && allOptions.IsSupersetOf(availableOptions)) { targetMetadata = usage; break; } } if (null == targetMetadata) { var args = new OptionsValidationExceptionArgs("Invalid command arguments provided."); throw new Exception<OptionsValidationExceptionArgs>(args); } try { return CreateInstanceInternal(targetMetadata, tokens); } catch (TargetInvocationException ex) { var argumentError = ex.InnerException as ArgumentException; if (null == argumentError) throw; string msg = string.Format("Invalid value for option '{0}'. {1}", argumentError.ParamName, argumentError.Message); var args = new OptionsValidationExceptionArgs(msg); throw new Exception<OptionsValidationExceptionArgs>(args); } catch (MissingMethodException) { var args = new OptionsValidationExceptionArgs("Invalid command arguments provided."); throw new Exception<OptionsValidationExceptionArgs>(args); } }
/// <summary> /// Initializes a new instance of the <see cref="WatchCommand" /> class. /// </summary> /// <param name="dir">Root directory of the project to monitor.</param> /// <param name="domain">Browser tabs domain to refresh.</param> /// <param name="sass">Enable instant SASS compilation.</param> /// <param name="typescript">Enable instant TypeScript compilation.</param> /// <param name="idle">Amout of milliseconds between tab refreshes.</param> /// <exception cref="Exception{OptionsValidationExceptionArgs}"> /// Indicates that specified arguments are invalid. /// </exception> public WatchCommand([Option("Root directory of the project to monitor")]string dir = null, [Option("Browser tabs domain to refresh")]string domain = "localhost", [Option("Enable instant SASS compilation")]bool sass = true, [Option("Enable instant TypeScript compilation")]bool typescript = true, [Option("Amount of milliseconds between tab refreshes")]uint idle = 300) { _dir = Path.GetFullPath(dir ?? "."); _domain = domain; _sass = sass; _typescript = typescript; _idle = idle; if (!Directory.Exists(_dir)) { var args = new OptionsValidationExceptionArgs("Specified project directory does not exist."); throw new Exception<OptionsValidationExceptionArgs>(args); } }
internal static IDictionary<string, OptionValue> GetTokens(string[] arguments, int offset = 0) { var retVal = new Dictionary<string, OptionValue>(arguments.Length); string currentOption = null; for (int index = offset; index < arguments.Length; index++) { string currentValue = arguments[index]; // currentValue is an option if it starts with option mark if (currentValue[0] == OptionMark) { if (null != currentOption) retVal.Add(currentOption, new OptionValue(null)); // Normalize option names to speed up lookup in the future currentOption = currentValue.Substring(1).ToLowerInvariant(); if (retVal.ContainsKey(currentOption)) { string msg = string.Format("Duplicate option '{0}' found", currentOption); var args = new OptionsValidationExceptionArgs(msg); throw new Exception<OptionsValidationExceptionArgs>(args); } } else { if (null == currentOption) { string msg = string.Format("No option associated with value '{0}'", currentValue); var args = new OptionsValidationExceptionArgs(msg); throw new Exception<OptionsValidationExceptionArgs>(args); } retVal.Add(currentOption, new OptionValue(currentValue)); currentOption = null; } } if (null != currentOption) retVal.Add(currentOption, new OptionValue(null)); return retVal; }
private object CreateInstanceInternal(OptionMetadata[] parameters, IDictionary<string, OptionValue> tokens) { object[] constructorParameters = new object[parameters.Length]; for (int index = 0; index < constructorParameters.Length; index++) { OptionMetadata parameter = parameters[index]; OptionValue token; object value; if (!tokens.TryGetValue(parameter.Name, out token)) { // don't use null as it will overwrite default values constructorParameters[index] = Type.Missing; continue; } if (!tokens[parameter.Name].TryChangeType(parameter.TargetType, out value)) { string msg = string.Format("Value '{0}' for option '{1}' is invalid. {2} expected", token, parameter.Name, parameter.TargetType.Name); var args = new OptionsValidationExceptionArgs(msg); throw new Exception<OptionsValidationExceptionArgs>(args); } constructorParameters[index] = value; } return Activator.CreateInstance(_metadata.CommandType, Flags, null, constructorParameters, CultureInfo.CurrentCulture); }