Browse Source
Note: I have made changes to a few methods due to .Net Core's APIs not matching .Net (full framework). But they are few and far between and the difference is academic here. So, I will not go in to detail. Featurewise, both versions should act the same.merge-requests/1/head
Craig Oates
7 years ago
19 changed files with 892 additions and 10 deletions
@ -0,0 +1,11 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Text; |
||||||
|
|
||||||
|
namespace CW_Core_Console |
||||||
|
{ |
||||||
|
public class ConsoleCommands |
||||||
|
{ |
||||||
|
public static string Test() => "Working"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
using Console.Waterworks.Core.Constants; |
||||||
|
using Console.Waterworks.Core.Loggers; |
||||||
|
using Console.Waterworks.Core.Specialists; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Reflection; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Assistants |
||||||
|
{ |
||||||
|
class CoOrdinatorAssistant |
||||||
|
{ |
||||||
|
internal void SetConsoleTitle(CW_Logger logger, ProgramInfoSpecialist progInfoSpec, ConsoleIOSpecialist consoleSpec) |
||||||
|
{ |
||||||
|
logger.LogInfoMessage("Attempting to set console title.."); |
||||||
|
var title = progInfoSpec.GetProductName(); |
||||||
|
if (!string.IsNullOrEmpty(title)) |
||||||
|
{ |
||||||
|
consoleSpec.SetConsoleTitle(title); |
||||||
|
logger.LogSuccessMessage("Console title is now set"); |
||||||
|
} |
||||||
|
else |
||||||
|
logger.LogErrorMessage("Unable to determine the program's title. Check the manifest file to make sure it has been set"); |
||||||
|
} |
||||||
|
|
||||||
|
internal void OutputProgramInfo(CW_Logger logger, ProgramInfoSpecialist progInfoSpec, ConsoleIOSpecialist consoleSpec) |
||||||
|
{ |
||||||
|
logger.LogInfoMessage("Attempting to retrieve program information.."); |
||||||
|
List<string> programInfo = progInfoSpec.GatherProgramInfomation(); |
||||||
|
logger.LogInfoMessage($"Found {programInfo.Count} out of {CW_Constants.PROGRAM_INFO_PROPERTIES_COUNT} properties"); |
||||||
|
logger.LogInfoMessage($"Writing program properties to console.."); |
||||||
|
consoleSpec.WriteProgramInfo(programInfo); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
internal void LogCommandGatheringAttempt(List<Type> commandClasses, Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> commandLibraries, CW_Logger logger) |
||||||
|
{ |
||||||
|
logger.LogInfoMessage($"Found {commandClasses.Count} command class(es).."); |
||||||
|
logger.LogInfoMessage($"Found {GetFoundCommandsTotal(commandLibraries)} command(s).."); |
||||||
|
logger.LogInfoMessage($"Found [{CW_Constants.COMMAND_CLASS_NAME}] class: { commandLibraries.ContainsKey(CW_Constants.COMMAND_CLASS_NAME)}"); |
||||||
|
logger.LogNoteMessage($"WaterWorks is only looking for the methods in the [{CW_Constants.COMMAND_CLASS_NAME}] class in the specified namespace. Everything else will be ignored"); |
||||||
|
logger.LogInfoMessage("Program is now initialised and awaiting input from the user. You are welcome ;-)"); |
||||||
|
} |
||||||
|
|
||||||
|
internal int GetFoundCommandsTotal(Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> commandLibraries) |
||||||
|
{ |
||||||
|
int total = 0; |
||||||
|
foreach (var currentClass in commandLibraries.Values) |
||||||
|
total += currentClass.Count; |
||||||
|
return total; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
using Console.Waterworks.Core.Models; |
||||||
|
using Console.Waterworks.Core.Specialists; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Assistants |
||||||
|
{ |
||||||
|
class CommandsAssistant |
||||||
|
{ |
||||||
|
internal bool ValidateClass(Command command, Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> commandLibraries) |
||||||
|
=> (commandLibraries.ContainsKey(command.ClassName)) ? true : false; |
||||||
|
|
||||||
|
internal bool ValidateCommand(Command command, Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> commandLibraries) |
||||||
|
{ |
||||||
|
var methodDict = commandLibraries[command.ClassName]; |
||||||
|
return (methodDict.ContainsKey(command.Name)) ? true : false; |
||||||
|
} |
||||||
|
|
||||||
|
internal string ExecuteBadCommandProcedure(Command command, ConsoleIOSpecialist consoleSpec) |
||||||
|
{ |
||||||
|
consoleSpec.WriteErrorSuffix(); |
||||||
|
return $"The command \'{command.Name}\' is not recognised."; |
||||||
|
} |
||||||
|
|
||||||
|
internal bool ValidateParamArguments(Command command, List<ParameterInfo> paramInfoList) |
||||||
|
{ |
||||||
|
var requiredParams = paramInfoList.Where(p => p.IsOptional == false); |
||||||
|
var optionalParams = paramInfoList.Where(p => p.IsOptional == true); |
||||||
|
int requiredCount = requiredParams.Count(); |
||||||
|
int optionalCount = optionalParams.Count(); |
||||||
|
int providedCount = command.Arguments.Count(); |
||||||
|
return (requiredCount > providedCount) ? false : true; |
||||||
|
} |
||||||
|
|
||||||
|
internal string ExecuteMissingArgumentProcedure(Command command, List<ParameterInfo> paramInfoList, ConsoleIOSpecialist consoleSpec) |
||||||
|
{ |
||||||
|
var requiredParams = paramInfoList.Where(p => p.IsOptional == false); |
||||||
|
var optionalParams = paramInfoList.Where(p => p.IsOptional == true); |
||||||
|
int requiredCount = requiredParams.Count(); |
||||||
|
int optionalCount = optionalParams.Count(); |
||||||
|
int providedCount = command.Arguments.Count(); |
||||||
|
return $"Missing required argument. {requiredCount} required, {optionalCount} optional, {providedCount} provided."; |
||||||
|
} |
||||||
|
|
||||||
|
internal List<object> GetParametreValueList(Command command, List<ParameterInfo> paramInfoList) |
||||||
|
{ |
||||||
|
var methodParameterValueList = new List<object>(); |
||||||
|
if (paramInfoList.Count() > 0) |
||||||
|
{ |
||||||
|
foreach (var param in paramInfoList) |
||||||
|
{ |
||||||
|
methodParameterValueList.Add(param.DefaultValue); |
||||||
|
} |
||||||
|
for (int i = 0; i < command.Arguments.Count(); i++) |
||||||
|
{ |
||||||
|
var methodParam = paramInfoList.ElementAt(i); |
||||||
|
var typeRequired = methodParam.ParameterType; |
||||||
|
object value = null; |
||||||
|
try |
||||||
|
{ |
||||||
|
value = CoercionSpecialist.CoerceArgument(typeRequired, command.Arguments.ElementAt(i)); |
||||||
|
methodParameterValueList.RemoveAt(i); |
||||||
|
methodParameterValueList.Insert(i, value); |
||||||
|
} |
||||||
|
catch (ArgumentException ex) |
||||||
|
{ |
||||||
|
string message = $"The value passed for argument '{methodParam.Name}' cannot be parsed to type '{typeRequired.Name}'"; // The exception message is being used instead, for now. |
||||||
|
throw new ArgumentException(ex.Message); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return methodParameterValueList; |
||||||
|
} |
||||||
|
|
||||||
|
internal Type BuildCommandLibraryClass(Command command, string commandsNamespace) |
||||||
|
{ |
||||||
|
Assembly programAssembly = Assembly.GetEntryAssembly(); |
||||||
|
Type commandLibraryClass = programAssembly.GetType($"{commandsNamespace}.{command.ClassName}"); |
||||||
|
return commandLibraryClass; |
||||||
|
} |
||||||
|
|
||||||
|
internal string InvokeCommand(Command command, Type typeInfo, object[] inputArguments) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
//var result = typeInfo.GetMethod(command.Name).Invoke(command.Name, inputArguments).ToString(); |
||||||
|
// return result.ToString(); |
||||||
|
return typeInfo.GetMethod(command.Name).Invoke(command.Name, inputArguments).ToString(); |
||||||
|
} |
||||||
|
catch (TargetInvocationException ex) |
||||||
|
{ |
||||||
|
throw ex.InnerException; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal object[] GetInputArguments(List<object> methodParametreValueList) |
||||||
|
{ |
||||||
|
object[] inputArguments = null; |
||||||
|
if (methodParametreValueList.Count > 0) |
||||||
|
inputArguments = methodParametreValueList.ToArray(); |
||||||
|
return inputArguments; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Attributes |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class DescriptionAttribute : Attribute |
||||||
|
{ |
||||||
|
public readonly string Description; |
||||||
|
|
||||||
|
public DescriptionAttribute(string description) |
||||||
|
{ |
||||||
|
Description = description; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Attributes |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class ListCommandAttribute : Attribute |
||||||
|
{ |
||||||
|
public readonly bool ShowCommand; |
||||||
|
public ListCommandAttribute() |
||||||
|
{ |
||||||
|
ShowCommand = true; |
||||||
|
} |
||||||
|
public ListCommandAttribute(bool show) |
||||||
|
{ |
||||||
|
ShowCommand = show; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Attributes |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class ParametersAttribute : Attribute |
||||||
|
{ |
||||||
|
public readonly string Parameters; |
||||||
|
public ParametersAttribute(string arguments) |
||||||
|
{ |
||||||
|
Parameters = arguments; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Attributes |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class UsageAttribute : Attribute |
||||||
|
{ |
||||||
|
public readonly string UsageExample; |
||||||
|
public UsageAttribute(string example) |
||||||
|
{ |
||||||
|
UsageExample = example; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
using Console.Waterworks.Core.CoOrdinators; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core |
||||||
|
{ |
||||||
|
public class CW_Liaison |
||||||
|
{ |
||||||
|
CoOrdinator _kevin = new CoOrdinator(); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Hands control over to Console.Waterworks.Core so the program can "run" as intended. |
||||||
|
/// </summary> |
||||||
|
/// <param name="consoleCommandsNamespace">The place where the program's command-methods are.</param> |
||||||
|
/// <param name="includeProgramInfo">Information about the console program, stated in Assembly Information.</param> |
||||||
|
public void Run(string consoleCommandsNamespace,bool includeProgramInfo) |
||||||
|
{ |
||||||
|
_kevin.PrepareConsoleEnvironment(); |
||||||
|
if (includeProgramInfo == true) _kevin.DisplayProgramInfo(); |
||||||
|
_kevin.RunProgram(consoleCommandsNamespace); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Displays all the attribute information it can find, attached to the command-methods, at run-time. |
||||||
|
/// </summary> |
||||||
|
/// <remarks> |
||||||
|
/// The returned string does not include the "help" information. |
||||||
|
/// It returns a string to indicate the method has finished collating the attribute information and displaying the information in the console. |
||||||
|
/// This method is intended to be use in a command-method. So, it aims to be compatible with command-method behaviour |
||||||
|
/// </remarks> |
||||||
|
/// <param name="consoleCommandsNamespace">The location of the programs command-method.</param> |
||||||
|
public string RequestHelpDocumentation(string consoleCommandsNamespace) => _kevin.DisplayHelpSection(consoleCommandsNamespace); |
||||||
|
} |
||||||
|
} |
@ -1,8 +0,0 @@ |
|||||||
using System; |
|
||||||
|
|
||||||
namespace Console.Waterworks.Core |
|
||||||
{ |
|
||||||
public class Class1 |
|
||||||
{ |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,96 @@ |
|||||||
|
using Console.Waterworks.Core.Assistants; |
||||||
|
using Console.Waterworks.Core.Constants; |
||||||
|
using Console.Waterworks.Core.Loggers; |
||||||
|
using Console.Waterworks.Core.Models; |
||||||
|
using Console.Waterworks.Core.Specialists; |
||||||
|
using System; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.CoOrdinators |
||||||
|
{ |
||||||
|
class CoOrdinator |
||||||
|
{ |
||||||
|
CoOrdinatorAssistant _assistant = new CoOrdinatorAssistant(); |
||||||
|
ProgramInfoSpecialist _progInfoSpec = new ProgramInfoSpecialist(); |
||||||
|
ConsoleIOSpecialist _consoleSpec = new ConsoleIOSpecialist(); |
||||||
|
CommandsSpecialist _commSpec = new CommandsSpecialist(); |
||||||
|
HelpSpecialist _helpSpec = new HelpSpecialist(); |
||||||
|
CW_Logger _logger = new CW_Logger(); |
||||||
|
|
||||||
|
internal void PrepareConsoleEnvironment() |
||||||
|
{ |
||||||
|
_logger.LogInfoMessage($"Preparing console.."); |
||||||
|
_consoleSpec.PrepareConsoleEnvironment(); |
||||||
|
_consoleSpec.SetInputPrompt($"{_progInfoSpec.GetProductName()}> "); |
||||||
|
_logger.LogSuccessMessage("Console environment is now setup"); |
||||||
|
} |
||||||
|
|
||||||
|
internal void DisplayProgramInfo() |
||||||
|
{ |
||||||
|
_logger.LogInfoMessage($"Displaying program information.."); |
||||||
|
_assistant.SetConsoleTitle(_logger, _progInfoSpec, _consoleSpec); |
||||||
|
_assistant.OutputProgramInfo(_logger, _progInfoSpec, _consoleSpec); |
||||||
|
} |
||||||
|
|
||||||
|
internal void RunProgram(string commandsNamespace) |
||||||
|
{ |
||||||
|
_logger.LogInfoMessage("Attempting to building commands library.."); |
||||||
|
var commandClasses = _commSpec.GetCommandClasses(commandsNamespace); |
||||||
|
var commandLibraries = _commSpec.GetCommandLibraries(commandClasses); |
||||||
|
_assistant.LogCommandGatheringAttempt(commandClasses, commandLibraries, _logger); |
||||||
|
while (true) |
||||||
|
{ |
||||||
|
var consoleInput = _consoleSpec.GetInputFromUser(); |
||||||
|
if (string.IsNullOrEmpty(consoleInput)) continue; |
||||||
|
try |
||||||
|
{ |
||||||
|
_logger.LogInfoMessage("Parsing input from user.."); |
||||||
|
var command = new Command(consoleInput, commandsNamespace, CW_Constants.COMMAND_CLASS_NAME); |
||||||
|
_logger.LogInfoMessage("Attempting to execute command.."); |
||||||
|
var result = _commSpec.ExecuteCommand(commandsNamespace, command, commandClasses, commandLibraries, _consoleSpec); |
||||||
|
_consoleSpec.WriteOutputToConsole(result); |
||||||
|
_logger.LogSuccessMessage("Command has been executed."); |
||||||
|
_logger.LogNoteMessage("An error message does not mean the command did not execute properly or sucessfully."); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
_logger.LogErrorMessage("Command was not successfully executed. See the error message in console for further details"); |
||||||
|
_consoleSpec.WriteErrorMessage(ex.Message); |
||||||
|
} |
||||||
|
_logger.LogInfoMessage("Resetting the console's formatting.."); |
||||||
|
_logger.LogNoteMessage("This is to make sure no error messages or one-off formating change corrupts the console environment."); |
||||||
|
_consoleSpec.ResetConsoleColour(); |
||||||
|
_logger.LogSuccessMessage("Console's formating has been reset"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal string DisplayHelpSection(string commandsNamespace) |
||||||
|
{ |
||||||
|
_logger.LogInfoMessage("Attempting to display help section.."); |
||||||
|
var commandClasses = _commSpec.GetCommandClasses(commandsNamespace); |
||||||
|
if (commandClasses.Count == 0) |
||||||
|
{ |
||||||
|
_logger.LogErrorMessage("Unable to find any help information. Make sure the commands hace the correct atrributes applied"); |
||||||
|
_consoleSpec.WriteErrorSuffix(); |
||||||
|
return "Unable to find help information"; |
||||||
|
} |
||||||
|
_logger.LogSuccessMessage("Found help information"); |
||||||
|
_logger.LogInfoMessage("Attempting to display the help information.."); |
||||||
|
_consoleSpec.WriteOutputToConsole("Displaying Help section..."); |
||||||
|
_consoleSpec.LineBreak(); |
||||||
|
var commandMembers = _helpSpec.GetCommandMembers(commandClasses); |
||||||
|
foreach (var command in commandMembers) |
||||||
|
{ |
||||||
|
if (_helpSpec.ListCommand(command) == true) |
||||||
|
{ |
||||||
|
_consoleSpec.WriteOutputToConsole($"Command Name: {command.Name}"); |
||||||
|
_consoleSpec.WriteOutputToConsole($"Parameters: {_helpSpec.GetParametres(command)}"); |
||||||
|
_consoleSpec.WriteOutputToConsole($"Description: {_helpSpec.GetDescription(command)}"); |
||||||
|
_consoleSpec.WriteOutputToConsole($"Example: {_helpSpec.GetUsageExamples(command)}"); |
||||||
|
_consoleSpec.LineBreak(); |
||||||
|
} |
||||||
|
} |
||||||
|
_logger.LogSuccessMessage("Help section displayed in the console"); |
||||||
|
return "End of Help section."; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
namespace Console.Waterworks.Core.Constants |
||||||
|
{ |
||||||
|
class CW_Constants |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// This represents the maximum number of properties the console can display when the client "DisplayProgramInfo" to true. |
||||||
|
/// This is used mostly for logging purposes. |
||||||
|
/// </summary> |
||||||
|
public const int PROGRAM_INFO_PROPERTIES_COUNT = 4; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// This specifies the name of the class Console.Waterworks.Core looks for when it tries to build its command library. |
||||||
|
/// This class should not be in Console.Waterworks.Core. |
||||||
|
/// It should be in the clients console program. |
||||||
|
/// </summary> |
||||||
|
public const string COMMAND_CLASS_NAME = "ConsoleCommands"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
using System.Diagnostics; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Loggers |
||||||
|
{ |
||||||
|
class CW_Logger |
||||||
|
{ |
||||||
|
internal void LogInfoMessage(string message) => Debug.WriteLine($"[Console.Waterworks.Core] INFO: {message}."); |
||||||
|
internal void LogNoteMessage(string message) => Debug.WriteLine($"[Console.Waterworks.Core] NOTE: {message}."); |
||||||
|
internal void LogSuccessMessage(string message) => Debug.WriteLine($"[Console.Waterworks.Core] SUCCESS: {message}."); |
||||||
|
internal void LogErrorMessage(string message) => Debug.WriteLine($"[Console.Waterworks.Core] ERROR: {message}."); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,77 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Text.RegularExpressions; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Models |
||||||
|
{ |
||||||
|
class Command |
||||||
|
{ |
||||||
|
public string Name { get; set; } |
||||||
|
public string ClassName { get; set; } |
||||||
|
|
||||||
|
List<string> _arguments; |
||||||
|
public IEnumerable<string> Arguments |
||||||
|
{ |
||||||
|
get { return _arguments; } |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Let us assume the end-user entered: [> Say "Hello, World!" 2]. |
||||||
|
* The input entered needs to be parse and seperated. |
||||||
|
* This is so ClassName and Arguments can be set. |
||||||
|
* Once everything has been parsed, _arguments should look like the following, |
||||||
|
* _arguments["Hello, World!", "2"] (This will be "mirrored" in Arguments). |
||||||
|
* Using the example at the top of this comment block, the end result will look something like, |
||||||
|
* ClassName = "Say" | Arguments = ["Hello, World!", "2"] |
||||||
|
* This object will then be used as the guide to locate the command-method this model describes. |
||||||
|
*/ |
||||||
|
public Command(string input, string commandsNamespace, string className) |
||||||
|
{ |
||||||
|
var splitInput = Regex.Split(input, "(?<=^[^\"]*(?:\"[^\"]*\"[^\"]*)*) (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); |
||||||
|
_arguments = new List<string>(); |
||||||
|
for (int i = 0; i < splitInput.Length; i++) |
||||||
|
{ |
||||||
|
if (i == 0) |
||||||
|
establishCommand(splitInput, i, className); |
||||||
|
else |
||||||
|
establishArguments(splitInput, i); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void establishCommand(string[] splitInput, int splitInputLocation, string nameOfClass) |
||||||
|
{ |
||||||
|
Name = splitInput[splitInputLocation]; |
||||||
|
ClassName = nameOfClass; // The default is "ConsoleCommands.cs" |
||||||
|
string[] splitCommandInput = splitInput[0].Split('.'); |
||||||
|
|
||||||
|
// This next part is a fancy feature and will almost never be used. |
||||||
|
if (splitCommandInput.Length == 2) |
||||||
|
{ |
||||||
|
// In short, it takes something like [> TestClass1.TestMethod2 "Hello, World"]. |
||||||
|
// And, it isolates the "TestClass1" and TestMethod2" parts. |
||||||
|
ClassName = splitCommandInput[0]; // "TestClass1" |
||||||
|
Name = splitCommandInput[1]; // TestMethod2" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void establishArguments(string[] splitInput, int splitInputLocation) |
||||||
|
{ |
||||||
|
var inputArgument = splitInput[splitInputLocation]; |
||||||
|
string argument = inputArgument; |
||||||
|
|
||||||
|
// This bit is just a check to see if the current part of the input is a quoted string. |
||||||
|
// If it is quoted text, "matches" will hold the various parts of the quote. |
||||||
|
var regex = new Regex("\"(.*?)\"", RegexOptions.Singleline); |
||||||
|
var matches = regex.Match(inputArgument); |
||||||
|
if (matches.Captures.Count > 0) |
||||||
|
{ |
||||||
|
// Each part of the quoted text is added to "argument" one-by-one. |
||||||
|
// The aim is to add the quoted text as a single line. |
||||||
|
var captureQuotedText = new Regex("[^\"]*[^\"]"); |
||||||
|
var quoted = captureQuotedText.Match(matches.Captures[0].Value); |
||||||
|
argument = quoted.Captures[0].Value; |
||||||
|
} |
||||||
|
_arguments.Add(argument); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,174 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Specialists |
||||||
|
{ |
||||||
|
internal static class CoercionSpecialist |
||||||
|
{ |
||||||
|
internal static object CoerceArgument(Type requiredType, string inputValue) |
||||||
|
{ |
||||||
|
var requiredTypeCode = Type.GetTypeCode(requiredType); |
||||||
|
string exceptionMessage = $"Cannnot coerce the input argument {inputValue} to required type {requiredType.Name}"; |
||||||
|
|
||||||
|
object result = null; |
||||||
|
switch (requiredTypeCode) |
||||||
|
{ |
||||||
|
case TypeCode.String: |
||||||
|
result = inputValue; |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.Int16: |
||||||
|
short number16; |
||||||
|
if (Int16.TryParse(inputValue, out number16)) |
||||||
|
{ |
||||||
|
result = number16; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.Int32: |
||||||
|
int number32; |
||||||
|
if (Int32.TryParse(inputValue, out number32)) |
||||||
|
{ |
||||||
|
result = number32; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.Int64: |
||||||
|
long number64; |
||||||
|
if (Int64.TryParse(inputValue, out number64)) |
||||||
|
{ |
||||||
|
result = number64; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.Boolean: |
||||||
|
bool trueFalse; |
||||||
|
if (bool.TryParse(inputValue, out trueFalse)) |
||||||
|
{ |
||||||
|
result = trueFalse; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.Byte: |
||||||
|
byte byteValue; |
||||||
|
if (byte.TryParse(inputValue, out byteValue)) |
||||||
|
{ |
||||||
|
result = byteValue; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.Char: |
||||||
|
char charValue; |
||||||
|
if (char.TryParse(inputValue, out charValue)) |
||||||
|
{ |
||||||
|
result = charValue; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeCode.DateTime: |
||||||
|
DateTime dateValue; |
||||||
|
if (DateTime.TryParse(inputValue, out dateValue)) |
||||||
|
{ |
||||||
|
result = dateValue; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
case TypeCode.Decimal: |
||||||
|
Decimal decimalValue; |
||||||
|
if (Decimal.TryParse(inputValue, out decimalValue)) |
||||||
|
{ |
||||||
|
result = decimalValue; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
case TypeCode.Double: |
||||||
|
Double doubleValue; |
||||||
|
if (Double.TryParse(inputValue, out doubleValue)) |
||||||
|
{ |
||||||
|
result = doubleValue; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
case TypeCode.Single: |
||||||
|
Single singleValue; |
||||||
|
if (Single.TryParse(inputValue, out singleValue)) |
||||||
|
{ |
||||||
|
result = singleValue; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
case TypeCode.UInt16: |
||||||
|
UInt16 uInt16Value; |
||||||
|
if (UInt16.TryParse(inputValue, out uInt16Value)) |
||||||
|
{ |
||||||
|
result = uInt16Value; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
case TypeCode.UInt32: |
||||||
|
UInt32 uInt32Value; |
||||||
|
if (UInt32.TryParse(inputValue, out uInt32Value)) |
||||||
|
{ |
||||||
|
result = uInt32Value; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
case TypeCode.UInt64: |
||||||
|
UInt64 uInt64Value; |
||||||
|
if (UInt64.TryParse(inputValue, out uInt64Value)) |
||||||
|
{ |
||||||
|
result = uInt64Value; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new ArgumentException(exceptionMessage); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
using Console.Waterworks.Core.Assistants; |
||||||
|
using Console.Waterworks.Core.Models; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Specialists |
||||||
|
{ |
||||||
|
class CommandsSpecialist |
||||||
|
{ |
||||||
|
CommandsAssistant _assistant = new CommandsAssistant(); |
||||||
|
|
||||||
|
internal List<Type> GetCommandClasses(string commandsNameSpace) |
||||||
|
{ |
||||||
|
string theNamespace = commandsNameSpace; |
||||||
|
var q = from t in Assembly.GetEntryAssembly().GetTypes() |
||||||
|
where t.GetTypeInfo().IsClass && t.Namespace == theNamespace |
||||||
|
select t; |
||||||
|
return q.ToList(); |
||||||
|
} |
||||||
|
|
||||||
|
internal Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> GetCommandLibraries(List<Type> commandClasses) |
||||||
|
{ |
||||||
|
var commandLibraries = new Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>>(); |
||||||
|
foreach (var commandClass in commandClasses) |
||||||
|
{ |
||||||
|
var methods = commandClass.GetMethods(BindingFlags.Static | BindingFlags.Public); |
||||||
|
var methodDictionary = new Dictionary<string, IEnumerable<ParameterInfo>>(); |
||||||
|
foreach (var method in methods) |
||||||
|
{ |
||||||
|
string commandName = method.Name; |
||||||
|
methodDictionary.Add(commandName, method.GetParameters()); |
||||||
|
} |
||||||
|
commandLibraries.Add(commandClass.Name, methodDictionary); |
||||||
|
} |
||||||
|
return commandLibraries; |
||||||
|
} |
||||||
|
|
||||||
|
internal string ExecuteCommand(string commandsNamespace, Command command, List<Type> commandClasses, Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> commandLibraries, ConsoleIOSpecialist consoleSpec) |
||||||
|
{ |
||||||
|
var classValidated = _assistant.ValidateClass(command, commandLibraries); |
||||||
|
var commandNameValidated = _assistant.ValidateCommand(command, commandLibraries); |
||||||
|
Dictionary<string, IEnumerable<ParameterInfo>> methodDictionary; |
||||||
|
if (classValidated != true || commandNameValidated != true) |
||||||
|
return _assistant.ExecuteBadCommandProcedure(command, consoleSpec); |
||||||
|
else |
||||||
|
methodDictionary = commandLibraries[command.ClassName]; |
||||||
|
var paramInfoList = methodDictionary[command.Name].ToList(); |
||||||
|
var paramsValidated = _assistant.ValidateParamArguments(command, paramInfoList); |
||||||
|
if (paramsValidated == false) |
||||||
|
return _assistant.ExecuteMissingArgumentProcedure(command, paramInfoList, consoleSpec); |
||||||
|
var methodParametreValueList = _assistant.GetParametreValueList(command, paramInfoList); |
||||||
|
var typeInfo = _assistant.BuildCommandLibraryClass(command, commandsNamespace); |
||||||
|
var inputArguments = _assistant.GetInputArguments(methodParametreValueList); |
||||||
|
var result = _assistant.InvokeCommand(command, typeInfo, inputArguments); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Specialists |
||||||
|
{ |
||||||
|
class ConsoleIOSpecialist |
||||||
|
{ |
||||||
|
string _consolePrompt; |
||||||
|
|
||||||
|
internal void PrepareConsoleEnvironment() |
||||||
|
{ |
||||||
|
#if DEBUG |
||||||
|
System.Console.BackgroundColor = ConsoleColor.DarkGray; |
||||||
|
System.Console.Clear(); |
||||||
|
System.Console.ForegroundColor = ConsoleColor.White; |
||||||
|
System.Console.WriteLine(" ------------ "); |
||||||
|
System.Console.WriteLine("| DEBUG MODE |"); |
||||||
|
System.Console.WriteLine(" ------------ "); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
internal void SetConsoleTitle(string title) => System.Console.Title = title; |
||||||
|
|
||||||
|
internal void SetInputPrompt(string prompt) => _consolePrompt = prompt; |
||||||
|
|
||||||
|
internal void WriteProgramInfo(List<string> programInfo) |
||||||
|
{ |
||||||
|
foreach (var line in programInfo) |
||||||
|
{ |
||||||
|
if (!string.IsNullOrEmpty(line)) System.Console.WriteLine(line); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal string GetInputFromUser() |
||||||
|
{ |
||||||
|
System.Console.ForegroundColor = ConsoleColor.Green; |
||||||
|
System.Console.Write(_consolePrompt); |
||||||
|
System.Console.ResetColor(); |
||||||
|
return System.Console.ReadLine(); |
||||||
|
} |
||||||
|
|
||||||
|
internal void WriteOutputToConsole(string message) => System.Console.WriteLine(message); |
||||||
|
|
||||||
|
internal void LineBreak() => System.Console.WriteLine(); |
||||||
|
|
||||||
|
internal void WriteErrorSuffix() |
||||||
|
{ |
||||||
|
System.Console.ForegroundColor = ConsoleColor.Red; |
||||||
|
System.Console.Write("[ERROR] "); |
||||||
|
} |
||||||
|
|
||||||
|
internal void WriteErrorMessage(string message) |
||||||
|
{ |
||||||
|
System.Console.ForegroundColor = ConsoleColor.Red; |
||||||
|
System.Console.WriteLine($"[ERROR] {message}"); |
||||||
|
System.Console.ResetColor(); |
||||||
|
} |
||||||
|
|
||||||
|
internal void ResetConsoleColour() => System.Console.ResetColor(); |
||||||
|
|
||||||
|
internal void WriteInfoSuffix() |
||||||
|
{ |
||||||
|
System.Console.ForegroundColor = ConsoleColor.Yellow; |
||||||
|
System.Console.Write("[INFO] "); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
using Console.Waterworks.Core.Attributes; |
||||||
|
using Console.Waterworks.Core.Loggers; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Reflection; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Specialists |
||||||
|
{ |
||||||
|
class HelpSpecialist |
||||||
|
{ |
||||||
|
CW_Logger _logger = new CW_Logger(); |
||||||
|
|
||||||
|
internal MemberInfo[] GetCommandMembers(List<Type> commandClasses) => commandClasses[0].GetMembers(); |
||||||
|
|
||||||
|
internal bool ListCommand(MemberInfo command) |
||||||
|
{ |
||||||
|
var customAttributes = GetCustomAttributes(command); |
||||||
|
var castedAttributes = CheckForAttributesType<ListCommandAttribute>(customAttributes); |
||||||
|
return (castedAttributes != null) ? castedAttributes.ShowCommand : false; |
||||||
|
} |
||||||
|
|
||||||
|
T CheckForAttributesType<T>(object[] attributes) |
||||||
|
{ |
||||||
|
T theAttributes = default(T); |
||||||
|
for (int i = 0; i < attributes.Length; i++) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
theAttributes = (T)attributes[i]; |
||||||
|
break; |
||||||
|
} |
||||||
|
catch (Exception) |
||||||
|
{ |
||||||
|
_logger.LogInfoMessage("The attempted casting attempt failed. Do not panic. This was expected"); |
||||||
|
} |
||||||
|
} |
||||||
|
return theAttributes; |
||||||
|
} |
||||||
|
|
||||||
|
object[] GetCustomAttributes(MemberInfo command) => command.GetCustomAttributes(true) as object[]; |
||||||
|
|
||||||
|
internal object GetParametres(MemberInfo command) |
||||||
|
{ |
||||||
|
var attributes = GetCustomAttributes(command); |
||||||
|
var castedAttributes = CheckForAttributesType<ParametersAttribute>(attributes); |
||||||
|
return (castedAttributes != null) ? castedAttributes.Parameters : "Parameters values could not be found"; |
||||||
|
} |
||||||
|
|
||||||
|
internal object GetDescription(MemberInfo command) |
||||||
|
{ |
||||||
|
var attributes = GetCustomAttributes(command); |
||||||
|
var castedAttributes = CheckForAttributesType<DescriptionAttribute>(attributes); |
||||||
|
return (castedAttributes != null) ? castedAttributes.Description : "Description could not be found"; |
||||||
|
} |
||||||
|
|
||||||
|
internal object GetUsageExamples(MemberInfo command) |
||||||
|
{ |
||||||
|
var attributes = GetCustomAttributes(command); |
||||||
|
var castedAttributes = CheckForAttributesType<UsageAttribute>(attributes); |
||||||
|
return (castedAttributes != null) ? castedAttributes.UsageExample : "Example could not be found"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Reflection; |
||||||
|
|
||||||
|
namespace Console.Waterworks.Core.Specialists |
||||||
|
{ |
||||||
|
class ProgramInfoSpecialist |
||||||
|
{ |
||||||
|
internal List<string> GatherProgramInfomation() |
||||||
|
{ |
||||||
|
var info = new List<string>() |
||||||
|
{ |
||||||
|
addProductLine(), |
||||||
|
addCompanyLine(), |
||||||
|
addCopyRightLine(), |
||||||
|
addProductDescription() |
||||||
|
}; |
||||||
|
return info; |
||||||
|
} |
||||||
|
|
||||||
|
private string addCopyRightLine() |
||||||
|
{ |
||||||
|
var assembly = Assembly.GetEntryAssembly(); |
||||||
|
var copyRightAttribute = assembly.GetCustomAttributes<AssemblyCopyrightAttribute>().FirstOrDefault(); |
||||||
|
return copyRightAttribute?.Copyright; |
||||||
|
} |
||||||
|
|
||||||
|
string addProductLine() |
||||||
|
{ |
||||||
|
var name = GetProductName(); |
||||||
|
var buildInfo = getBuildInfo(); |
||||||
|
return (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(buildInfo)) ? $"{name} {buildInfo}" : null; |
||||||
|
} |
||||||
|
|
||||||
|
string addCompanyLine() |
||||||
|
{ |
||||||
|
var assembly = Assembly.GetEntryAssembly(); |
||||||
|
var companyAttribute = assembly.GetCustomAttributes<AssemblyCompanyAttribute>().FirstOrDefault(); |
||||||
|
return companyAttribute?.Company; |
||||||
|
} |
||||||
|
|
||||||
|
string addProductDescription() |
||||||
|
{ |
||||||
|
var assembly = Assembly.GetEntryAssembly(); |
||||||
|
var descriptionAttribute = assembly.GetCustomAttributes<AssemblyDescriptionAttribute>().FirstOrDefault(); |
||||||
|
return descriptionAttribute?.Description; |
||||||
|
} |
||||||
|
|
||||||
|
internal string GetProductName() |
||||||
|
{ |
||||||
|
var assembly = Assembly.GetEntryAssembly(); |
||||||
|
var productAttribute = assembly.GetCustomAttributes<AssemblyProductAttribute>().FirstOrDefault(); |
||||||
|
return productAttribute?.Product; |
||||||
|
} |
||||||
|
|
||||||
|
string getBuildInfo() => Assembly.GetEntryAssembly().GetName().Version.ToString(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue