예제 #1
0
        /// <summary>
        /// Generate the usage string based on the given type's attributes.
        /// <para>Optional positional parameters will be shown in square brackets.</para>
        /// <para>Required options will have an asterix prefix.</para>
        /// </summary>
        /// <param name="executableName"></param>
        /// <param name="indentationSpaces"></param>
        /// <returns></returns>
        public string Usage(string executableName = null, int indentationSpaces = 4)
        {
            string executable = Environment.GetCommandLineArgs()[0];

            executableName = executableName ?? executable;
            string indentation = string.Join("", new int[indentationSpaces].Select(s => " "));

            StringBuilder usage = new StringBuilder();

            usage.AppendFormat("Usage: {0} [options] ", executableName);

            IOrderedEnumerable <MemberInfo> positionalParams = Utils.GetParameterMembers <T, PositionalParameterAttribute>(bindingFlags)
                                                               .OrderBy(member => member.GetCustomAttribute <PositionalParameterAttribute>().Index);
            IOrderedEnumerable <MemberInfo> optionParams = Utils.GetParameterMembers <T, ParameterAttribute>(bindingFlags)
                                                           .OrderBy(member => member.GetCustomAttribute <ParameterAttribute>().Names[0]);
            IOrderedEnumerable <MemberInfo> commands = Utils.GetParameterMembers <T, CommandAttribute>(bindingFlags)
                                                       .OrderBy(member => member.GetCustomAttribute <CommandAttribute>().Names[0]);

            foreach (MemberInfo member in positionalParams)
            {
                // Print example line
                PositionalParameterAttribute param = member.GetCustomAttribute <PositionalParameterAttribute>();

                if (ParamRequired <T>(defaultObject, param, member))
                {
                    usage.AppendFormat("<{0}> ", param.Name);
                }
                else
                {
                    usage.AppendFormat("[{0}] ", param.Name);
                }
            }

            if (commands.Count() > 0)
            {
                usage.Append("<command>");
            }

            usage.AppendLine();

            foreach (MemberInfo member in positionalParams)
            {
                PositionalParameterAttribute param = member.GetCustomAttribute <PositionalParameterAttribute>();
                // Print positional argument descriptions
                if (param.Description != null)
                {
                    usage.AppendFormat("{0}{1}{2}{3}\n", indentation, param.Name, indentation, param.Description);
                }
            }

            if (commands.Count() > 0)
            {
                usage.AppendLine("Commands:");

                foreach (MemberInfo member in commands)
                {
                    CommandAttribute param = member.GetCustomAttribute <CommandAttribute>();
                    // Print command descriptions
                    if (param.Description != null)
                    {
                        usage.AppendFormat("{0}{1}{2}{3}\n", indentation, param.Names[0], indentation, param.Description);
                    }
                    else
                    {
                        usage.AppendFormat("{0}{1}\n", indentation, param.Names[0]);
                    }
                }
            }

            usage.AppendLine("Options:");

            foreach (MemberInfo member in optionParams)
            {
                ParameterAttribute param        = member.GetCustomAttribute <ParameterAttribute>();
                object             defaultValue = GetDefaultValue <T>(defaultObject, member);
                bool required = ParamRequired <T>(defaultObject, param, member);

                usage.Append(indentation).Append(required ? "* " : "  ");

                for (int i = 0; i < param.Names.Length; i++)
                {
                    if (i != 0)
                    {
                        usage.Append(", ");
                    }
                    usage.Append(param.Names[i]);
                }
                usage.AppendLine();

                if (param.Description != null)
                {
                    usage.AppendFormat("{0}{1}{2}\n", indentation, indentation, param.Description);
                }

                if (!required && defaultValue != null)
                {
                    usage.AppendFormat("{0}{1}Default: {2}\n", indentation, indentation, defaultValue);
                }
            }

            return(usage.ToString());
        }
예제 #2
0
        /// <summary>
        /// Parse the arguments added to this object and serialize them into an existing instance of a T object.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="separators"></param>
        /// <returns></returns>
        public T Parse(T obj)
        {
            /*
             * Parse arguments
             */
            RawArguments <T> rawArgs = new RawArguments <T>(bindingFlags)
                                       .Parse(args, separators);

            /*
             * Set named arguments
             */
            foreach (MemberInfo member in Utils.GetParameterMembers <T, ParameterAttribute>(bindingFlags))
            {
                ParameterAttribute param = member.GetCustomAttribute <ParameterAttribute>();

                if (member.Type() == typeof(bool))
                {
                    SetValue(
                        obj,
                        member,
                        param.Keys.Any(name => rawArgs.GetBoolean(name))
                        );
                }
                else
                {
                    string matchingKey = rawArgs.GetMatchingKey(param.Keys);

                    if (matchingKey != null)
                    {
                        SetValue(obj, member, param, matchingKey, rawArgs[matchingKey]);
                    }
                    else if (ParamRequired <T>(defaultObject, param, member))
                    {
                        // Required parameter missing
                        throw new ParameterMissingException(param);
                    }
                }
            }

            /*
             * Set positional arguments
             */
            foreach (MemberInfo member in Utils.GetParameterMembers <T, PositionalParameterAttribute>(bindingFlags))
            {
                PositionalParameterAttribute param = member.GetCustomAttribute <PositionalParameterAttribute>();

                if (param.Index < rawArgs.PositionalArguments)
                {
                    SetValue(obj, member, param, param.Name, rawArgs[(int)param.Index]);
                }
                else if (ParamRequired <T>(defaultObject, param, member))
                {
                    // Required parameter missing
                    throw new ParameterMissingException(param);
                }
            }

            /*
             * Set the positional arguments list
             */
            foreach (MemberInfo member in Utils.GetParameterMembers <T, PositionalParameterListAttribute>(bindingFlags))
            {
                if (member.Type().IsArray)
                {
                    SetValue(obj, member, rawArgs.GetPositionalArguments().ToArray());
                }
                else
                {
                    SetValue(obj, member, rawArgs.GetPositionalArguments());
                }
            }

            /*
             * Check if a command was entered
             */
            if (rawArgs.Command != null)
            {
                string[]   commandArgs   = args.Skip(rawArgs.CommandIndex + 1).ToArray();
                MemberInfo commandMember = Utils.GetCommandWithName <T>(rawArgs.Command, bindingFlags);
                Type       commandType   = commandMember.Type();

                Type   parserType = typeof(CommanderParser <>).MakeGenericType(commandType);
                object parser     = Activator.CreateInstance(parserType, commandArgs);

                // Set options
                parserType.GetTypeInfo().GetMethod("Separators", new Type[] { typeof(Separators) })
                .Invoke(parser, new object[] { separators });
                parserType.GetTypeInfo().GetMethod("Bindings", new Type[] { typeof(BindingFlags) })
                .Invoke(parser, new object[] { bindingFlags });


                // Parse the command
                object command = parserType.GetTypeInfo().GetMethod("Parse", new Type[] { typeof(string[]) })
                                 .Invoke(parser, new object[] { commandArgs });

                // Set the command back to the object
                SetValue(obj, commandMember, command);

                // Call the command handlers
                if (typeof(ICommand).GetTypeInfo().IsAssignableFrom(commandType))
                {
                    // First the handler on the command object, if it implements ICommand
                    (command as ICommand).Execute(obj);
                }
                foreach (MethodInfo handler in Utils.GetMethods <T, CommandHandlerAttribute>(bindingFlags))
                {
                    // Then check if the parent object has any handler for this command

                    ParameterInfo[] handlerParams = handler.GetParameters();

                    if (handlerParams.Length == 1 && handlerParams[0].ParameterType == commandType)
                    {
                        handler.Invoke(obj, new object[] { command });
                    }
                }
            }
            else if (Utils.GetCommandNames <T>(bindingFlags).Count > 0)
            {
                // The are commands, but no command was passed
                throw new CommandMissingException();
            }

            return(obj);
        }