Browse Source

Merge branch 'develop'

merge-requests/1/head
Craig Oates 7 years ago
parent
commit
26c2e7ac58
  1. 63
      .gitattributes
  2. 261
      .gitignore
  3. 6
      Console.Waterworks/CW_Console/App.config
  4. 60
      Console.Waterworks/CW_Console/CW_Console.csproj
  5. 106
      Console.Waterworks/CW_Console/ConsoleCommands.cs
  6. 15
      Console.Waterworks/CW_Console/Program.cs
  7. 39
      Console.Waterworks/CW_Console/Properties/AssemblyInfo.cs
  8. 31
      Console.Waterworks/Console.Waterworks.sln
  9. 52
      Console.Waterworks/Console.Waterworks/Assistants/CoOrdinatorAssistant.cs
  10. 105
      Console.Waterworks/Console.Waterworks/Assistants/CommandsAssistant.cs
  11. 15
      Console.Waterworks/Console.Waterworks/Attributes/DescriptionAttribute.cs
  12. 18
      Console.Waterworks/Console.Waterworks/Attributes/ListCommandAttribute.cs
  13. 14
      Console.Waterworks/Console.Waterworks/Attributes/ParametersAttribute.cs
  14. 14
      Console.Waterworks/Console.Waterworks/Attributes/UsageAttribute.cs
  15. 32
      Console.Waterworks/Console.Waterworks/CW_Liaison.cs
  16. 96
      Console.Waterworks/Console.Waterworks/CoOrdinators/CoOrdinator.cs
  17. 70
      Console.Waterworks/Console.Waterworks/Console.Waterworks.csproj
  18. 18
      Console.Waterworks/Console.Waterworks/Constants/CW_Constants.cs
  19. 12
      Console.Waterworks/Console.Waterworks/Loggers/CW_Logger.cs
  20. 70
      Console.Waterworks/Console.Waterworks/Models/Command.cs
  21. 38
      Console.Waterworks/Console.Waterworks/Properties/AssemblyInfo.cs
  22. 174
      Console.Waterworks/Console.Waterworks/Specialists/CoercionSpecialist.cs
  23. 60
      Console.Waterworks/Console.Waterworks/Specialists/CommandsSpecialist.cs
  24. 67
      Console.Waterworks/Console.Waterworks/Specialists/ConsoleIOSpecialist.cs
  25. 63
      Console.Waterworks/Console.Waterworks/Specialists/HelpSpecialist.cs
  26. 70
      Console.Waterworks/Console.Waterworks/Specialists/ProgramInfoSpecialist.cs
  27. BIN
      Console.Waterworks/Console.Waterworks/WaterWorksIcon.ico
  28. 102
      README.md

63
.gitattributes vendored

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

261
.gitignore vendored

@ -0,0 +1,261 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

6
Console.Waterworks/CW_Console/App.config

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
</startup>
</configuration>

60
Console.Waterworks/CW_Console/CW_Console.csproj

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E26D7001-2A4E-4618-8C27-8BF504993EE9}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>CW_Console</RootNamespace>
<AssemblyName>CW_Console</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ConsoleCommands.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Console.Waterworks\Console.Waterworks.csproj">
<Project>{d1354760-61f7-4aee-8d6f-e78a463ee3c9}</Project>
<Name>Console.Waterworks</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

106
Console.Waterworks/CW_Console/ConsoleCommands.cs

@ -0,0 +1,106 @@
using Console.Waterworks;
using Console.Waterworks.Attributes;
using System;
namespace CW_Console
{
public class ConsoleCommands
{
[ListCommand()]
[Description("Displays the Help section at run-time")]
[Parameters("None")]
[Usage("CW_Console> Help")]
public static string Help()
{
CW_Liaison liaison = new CW_Liaison();
return liaison.RequestHelpDocumentation("CW_Console");
}
[ListCommand()]
[Description("Outputs to the console the command has been completed.")]
[Parameters("None")]
[Usage("CW_Console> Command1")]
public static string Command1() => "Command1 has completed";
[ListCommand()]
[Description("Repeats back to the user the string they entered.")]
[Parameters("<string> input")]
[Usage("CW_Console> Command2 \"Hello, World.\"")]
public static string Command2(string input) => $"Command2 has completed... {input} was entered";
[ListCommand()]
[Description("Repeats back to the user what int they entered.")]
[Parameters("<int> int1")]
[Usage("CW_Console> Command3 31")]
public static string Command3(int input) => $"Command3 has completed... The number {input} was entered";
[ListCommand()]
[Description("Takes the two ints and adds them together.")]
[Parameters("<int> int, <int> int2")]
[Usage("CW_Console> Command4 31 10")]
public static string Command4(int int1, int int2) => $"Command4 has completed... {int1} and {int2} was entered and make {int1 + int2} when added together";
[ListCommand()]
[Description("Take the int and double and adds them together.")]
[Parameters("<int> int1, <double1> double1")]
[Usage("CW_Console> Command5 31 25.4")]
public static string Command5(int int1, double double1) => $"Command5 has completed... {int1} and {double1} was entered and make {int1 + double1} when added together";
[ListCommand()]
[Description("Terminates the program.")]
[Parameters("None")]
[Usage("CW_Console> Quit")]
public static void Quit() => Environment.Exit(-1);
#region Alias-Methods
/*
* A NOTE ABOUT ALIAS-METHODS - DELETE AFTER READING
* =========================================================
* These methods are shorthand versions of the ones above.
* For the most part, this is a hack.
* But, it is a useful one.
* When new users start using your console program, they need help getting started.
* This is why I recommend using descriptive names for your command-methods.
* But, when your users become more familiar with the program, they will want terser commands.
* They will no longer need their hand holding. This is where these alias-commands come in.
*/
[ListCommand(false)] // change to true or delete "false" for it to show at run-time.
[Description("Alias for Command1. See Command1 for details.")]
[Parameters("None")]
[Usage("CW_Console> c1")]
public static string c1() => Command1();
[ListCommand(false)]
[Description("Alias for Command2. See Command2 for details.")]
[Parameters("None")]
[Usage("CW_Console> c2 \"Hello, World.\"")]
public static string c2(string input) => Command2(input);
[ListCommand(false)]
[Description("Alias for Command3. See Command3 for details.")]
[Parameters("None")]
[Usage("CW_Console> c3 78")]
public static string c3(int input) => Command3(input);
[ListCommand(false)]
[Description("Alias for Command4. See Command4 for details.")]
[Parameters("None")]
[Usage("CW_Console> c4 24 67")]
public static string c4(int int1, int int2) => Command4(int1, int2);
[ListCommand(false)]
[Description("Alias for Command5. See Command5 for details.")]
[Parameters("None")]
[Usage("CW_Console> c5 12 46.3")]
public static string c5(int int1, double double1) => Command5(int1, double1);
[ListCommand(false)]
[Description("Alias for Quit. See Quit for details.")]
[Parameters("None")]
[Usage("CW_Console> quit")]
public static void quit() => Quit();
#endregion
}
}

15
Console.Waterworks/CW_Console/Program.cs

@ -0,0 +1,15 @@
using Console.Waterworks;
namespace CW_Console
{
class Program
{
static void Main(string[] args)
{
CW_Liaison bob = new CW_Liaison();
bob.Run("CW_Console", true);
// That is it. You are done here.
// Head over to ConsoleCommands.cs to begin adding features...
}
}
}

39
Console.Waterworks/CW_Console/Properties/AssemblyInfo.cs

@ -0,0 +1,39 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CW_Console")]
[assembly: AssemblyDescription("This is the console program for testing the Console.Waterworks Nuget package.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Craig Oates")]
[assembly: AssemblyProduct("CW_Console")]
[assembly: AssemblyCopyright("Copyright © 2017 Craig Oates")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e26d7001-2a4e-4618-8c27-8bf504993ee9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: NeutralResourcesLanguage("en-GB")]

31
Console.Waterworks/Console.Waterworks.sln

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console.Waterworks", "Console.Waterworks\Console.Waterworks.csproj", "{D1354760-61F7-4AEE-8D6F-E78A463EE3C9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CW_Console", "CW_Console\CW_Console.csproj", "{E26D7001-2A4E-4618-8C27-8BF504993EE9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D1354760-61F7-4AEE-8D6F-E78A463EE3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1354760-61F7-4AEE-8D6F-E78A463EE3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1354760-61F7-4AEE-8D6F-E78A463EE3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1354760-61F7-4AEE-8D6F-E78A463EE3C9}.Release|Any CPU.Build.0 = Release|Any CPU
{E26D7001-2A4E-4618-8C27-8BF504993EE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E26D7001-2A4E-4618-8C27-8BF504993EE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E26D7001-2A4E-4618-8C27-8BF504993EE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E26D7001-2A4E-4618-8C27-8BF504993EE9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BC405CAC-EBE7-4A72-AEE1-93C99AE240E3}
EndGlobalSection
EndGlobal

52
Console.Waterworks/Console.Waterworks/Assistants/CoOrdinatorAssistant.cs

@ -0,0 +1,52 @@
using Console.Waterworks.Constants;
using Console.Waterworks.Loggers;
using Console.Waterworks.Specialists;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Console.Waterworks.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;
}
}
}

105
Console.Waterworks/Console.Waterworks/Assistants/CommandsAssistant.cs

@ -0,0 +1,105 @@
using Console.Waterworks.Models;
using Console.Waterworks.Specialists;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Console.Waterworks.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.InvokeMember(command.Name, BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, inputArguments);
return result.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;
}
}
}

15
Console.Waterworks/Console.Waterworks/Attributes/DescriptionAttribute.cs

@ -0,0 +1,15 @@
using System;
namespace Console.Waterworks.Attributes
{
[AttributeUsage(AttributeTargets.All)]
public class DescriptionAttribute : Attribute
{
public readonly string Description;
public DescriptionAttribute(string description)
{
Description = description;
}
}
}

18
Console.Waterworks/Console.Waterworks/Attributes/ListCommandAttribute.cs

@ -0,0 +1,18 @@
using System;
namespace Console.Waterworks.Attributes
{
[AttributeUsage(AttributeTargets.All)]
public class ListCommandAttribute : Attribute
{
public readonly bool ShowCommand;
public ListCommandAttribute()
{
ShowCommand = true;
}
public ListCommandAttribute(bool show)
{
ShowCommand = show;
}
}
}

14
Console.Waterworks/Console.Waterworks/Attributes/ParametersAttribute.cs

@ -0,0 +1,14 @@
using System;
namespace Console.Waterworks.Attributes
{
[AttributeUsage(AttributeTargets.All)]
public class ParametersAttribute : Attribute
{
public readonly string Parameters;
public ParametersAttribute(string arguments)
{
Parameters = arguments;
}
}
}

14
Console.Waterworks/Console.Waterworks/Attributes/UsageAttribute.cs

@ -0,0 +1,14 @@
using System;
namespace Console.Waterworks.Attributes
{
[AttributeUsage(AttributeTargets.All)]
public class UsageAttribute : Attribute
{
public readonly string UsageExample;
public UsageAttribute(string example)
{
UsageExample = example;
}
}
}

32
Console.Waterworks/Console.Waterworks/CW_Liaison.cs

@ -0,0 +1,32 @@
using Console.Waterworks.CoOrdinators;
namespace Console.Waterworks
{
public class CW_Liaison
{
CoOrdinator _kevin = new CoOrdinator();
/// <summary>
/// Hands control over to Console.Waterworks 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);
}
}

96
Console.Waterworks/Console.Waterworks/CoOrdinators/CoOrdinator.cs

@ -0,0 +1,96 @@
using Console.Waterworks.Assistants;
using Console.Waterworks.Constants;
using Console.Waterworks.Loggers;
using Console.Waterworks.Models;
using Console.Waterworks.Specialists;
using System;
namespace Console.Waterworks.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.";
}
}
}

70
Console.Waterworks/Console.Waterworks/Console.Waterworks.csproj

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D1354760-61F7-4AEE-8D6F-E78A463EE3C9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Console.Waterworks</RootNamespace>
<AssemblyName>Console.Waterworks</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>WaterWorksIcon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Assistants\CommandsAssistant.cs" />
<Compile Include="Assistants\CoOrdinatorAssistant.cs" />
<Compile Include="Attributes\DescriptionAttribute.cs" />
<Compile Include="Attributes\ListCommandAttribute.cs" />
<Compile Include="Attributes\ParametersAttribute.cs" />
<Compile Include="Attributes\UsageAttribute.cs" />
<Compile Include="Constants\CW_Constants.cs" />
<Compile Include="CoOrdinators\CoOrdinator.cs" />
<Compile Include="CW_Liaison.cs" />
<Compile Include="Loggers\CW_Logger.cs" />
<Compile Include="Models\Command.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Specialists\CoercionSpecialist.cs" />
<Compile Include="Specialists\CommandsSpecialist.cs" />
<Compile Include="Specialists\ConsoleIOSpecialist.cs" />
<Compile Include="Specialists\HelpSpecialist.cs" />
<Compile Include="Specialists\ProgramInfoSpecialist.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Content Include="WaterWorksIcon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

18
Console.Waterworks/Console.Waterworks/Constants/CW_Constants.cs

@ -0,0 +1,18 @@
namespace Console.Waterworks.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 looks for when it tries to build its command library.
/// This class should not be in Console.WaterWorks.
/// It should be in the clients console program.
/// </summary>
public const string COMMAND_CLASS_NAME = "ConsoleCommands";
}
}

12
Console.Waterworks/Console.Waterworks/Loggers/CW_Logger.cs

@ -0,0 +1,12 @@
using System.Diagnostics;
namespace Console.Waterworks.Loggers
{
class CW_Logger
{
internal void LogInfoMessage(string message) => Debug.WriteLine($"[Console.WaterWorks] INFO: {message}.");
internal void LogNoteMessage(string message) => Debug.WriteLine($"[Console.WaterWorks] NOTE: {message}.");
internal void LogSuccessMessage(string message) => Debug.WriteLine($"[Console.WaterWorks] SUCCESS: {message}.");
internal void LogErrorMessage(string message) => Debug.WriteLine($"[Console.WaterWorks] ERROR: {message}.");
}
}

70
Console.Waterworks/Console.Waterworks/Models/Command.cs

@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Console.Waterworks.Models
{
class Command
{
public string Name { get; set; }
public string ClassName { get; set; }
private List<string> _arguments;
public IEnumerable<string> Arguments
{
get
{
return _arguments;
}
}
public Command(string input, string commandsNamespace, string className)
{
// Ugly regex to split string on spaces, but preserve quoted text intact:
var stringArray =
Regex.Split(input, "(?<=^[^\"]*(?:\"[^\"]*\"[^\"]*)*) (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
_arguments = new List<string>();
for (int i = 0; i < stringArray.Length; i++)
{
// The first element is always the command:
if (i == 0)
{
Name = stringArray[i];
// Set the class name
ClassName = className;
string[] s = stringArray[0].Split('.');
if (s.Length == 2)
{
ClassName = s[0];
Name = s[1];
}
}
else
{
var inputArgument = stringArray[i];
// Assume that most of the time, the input argument is NOT quoted text:
string argument = inputArgument;
// Is the argument a quoted text string?
var regex = new Regex("\"(.*?)\"", RegexOptions.Singleline);
var match = regex.Match(inputArgument);
// If it IS quoted, there will be at least one capture:
if (match.Captures.Count > 0)
{
// Get the unquoted text from within the qoutes:
var captureQuotedText = new Regex("[^\"]*[^\"]");
var quoted = captureQuotedText.Match(match.Captures[0].Value);
// The argument should include all text from between the quotes
// as a single string:
argument = quoted.Captures[0].Value;
}
_arguments.Add(argument);
}
}
}
}
}

38
Console.Waterworks/Console.Waterworks/Properties/AssemblyInfo.cs

@ -0,0 +1,38 @@
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Console.Waterworks")]
[assembly: AssemblyDescription("Console.Waterworks is a Nuget package which helps you write command-based console programs in .Net.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Console.Waterworks")]
[assembly: AssemblyCopyright("Copyright © 2017 Craig Oates")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d1354760-61f7-4aee-8d6f-e78a463ee3c9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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("0.1.0.0")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: NeutralResourcesLanguage("en-GB")]

174
Console.Waterworks/Console.Waterworks/Specialists/CoercionSpecialist.cs

@ -0,0 +1,174 @@
using System;
namespace Console.Waterworks.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;
}
}
}

60
Console.Waterworks/Console.Waterworks/Specialists/CommandsSpecialist.cs

@ -0,0 +1,60 @@
using Console.Waterworks.Assistants;
using Console.Waterworks.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Console.Waterworks.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.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;
}
}
}

67
Console.Waterworks/Console.Waterworks/Specialists/ConsoleIOSpecialist.cs

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
namespace Console.Waterworks.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] ");
}
}
}

63
Console.Waterworks/Console.Waterworks/Specialists/HelpSpecialist.cs

@ -0,0 +1,63 @@
using Console.Waterworks.Attributes;
using Console.Waterworks.Loggers;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Console.Waterworks.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);
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";
}
}
}

70
Console.Waterworks/Console.Waterworks/Specialists/ProgramInfoSpecialist.cs

@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Console.Waterworks.Specialists
{
class ProgramInfoSpecialist
{
internal List<string> GatherProgramInfomation()
{
var info = new List<string>()
{
addProductLine(),
addCompanyLine(),
addCopyRightLine(),
addProductDescription()
};
return info;
}
private string addCopyRightLine()
{
Assembly assembly = Assembly.GetEntryAssembly();
var copyRightAttribute = assembly
.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false)
.OfType<AssemblyCopyrightAttribute>()
.FirstOrDefault();
return (copyRightAttribute != null) ? copyRightAttribute.Copyright : null;
}
string addProductLine()
{
var name = GetProductName();
var buildInfo = getBuildInfo();
return (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(buildInfo)) ? $"{name} {buildInfo}" : null;
}
string addCompanyLine()
{
Assembly assembly = Assembly.GetEntryAssembly();
var companyAttribute = assembly
.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false)
.OfType<AssemblyCompanyAttribute>()
.FirstOrDefault();
return (companyAttribute != null) ? companyAttribute.Company : null;
}
string addProductDescription()
{
Assembly assembly = Assembly.GetEntryAssembly();
var descriptionAttribute = assembly
.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false)
.OfType<AssemblyDescriptionAttribute>()
.FirstOrDefault();
return (descriptionAttribute != null) ? descriptionAttribute.Description : null;
}
internal string GetProductName()
{
Assembly assembly = Assembly.GetEntryAssembly();
var productAttribute = assembly
.GetCustomAttributes(typeof(AssemblyProductAttribute), false)
.OfType<AssemblyProductAttribute>()
.FirstOrDefault();
return (productAttribute != null) ? productAttribute.Product : null;
}
string getBuildInfo() => Assembly.GetEntryAssembly().GetName().Version.ToString();
}
}

BIN
Console.Waterworks/Console.Waterworks/WaterWorksIcon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

102
README.md

@ -1,2 +1,100 @@
# Console.Waterworks
Console.Waterworks is a Nuget package which helps you write command-based console programs in .Net.
# Console.Waterworks - This is incomplete
Console.Waterworks is a Nuget package. It aims to help you write extendable and command-based console programs in C# and .Net.
One of the main struggles with writing software is the need to write "plumbing code". It is the code which does not solve the main problem but it is necessary for us to reach a solution. This is why we all feel frustrated when we need to write it. It feels like we are going the long way round to that dream holiday in the sun. This is why I created Console.Waterworks. I believe we should face frustration when it finds us and only then. Why go looking for it?
Amongst other things, Console.Waterworks has this one very handy trick. It allows you to write methods which become a run-time command -- which is quite the time saver. When you use Console.Waterworks, you, also, do not need to parse end-user input. The reason why is because Console.Waterworks does it for you. This means, when people run your program, they type the method name in and your code begins excuting. On top of that, Console.Waterworks handles bad input and method parameters, as well.
Do not panic if none of what I just said made no sense. I threw a lot of information at you in a short span of time. It is okay and not unexpected. Because of this, I have prepared a gif showing Console.Waterworks in action. Please feel free to check it out. It should help explain what Console.Waterwork is and how it works.
**Insert gif here**
## Pre-Requisites
To use Console.Waterworks, I recommend you meet the following pre-requisites:
- You have experience with C#.
- You can create a .Net console program in Visual Studio 2017 or Visual Studio Code.
- You have experience with Nuget.
- You have Microsoft .Net Framework 4.7 or higher.
## Quick Start
Before continuing... I am skipping the part about creating a .Net console program. This is because I assume you know to do that. I am, also, assuming you are using Visual Studio 2017 and C# (and not VB or F#).
1 Add Console.Waterworks to your project via Nuget. You can do this using Visual Studio's (2017) Package Manager GUI. Or, you can use the Package Manager Console. Here is the command for the PM Console,
```powershell
Install-Package Console.Waterworks -Version 0.1.0-alpha1
```
2 Create a class called `ConsoleCommands`. It can go anywhere as long as it is in the same project as the console program project.
3 Make a note of the `ConsoleCommands` namespace.
4 Head to the `Main` method is `Program.cs` and add the following lines of code,
```c#
public static void Main(string[] args)
{
CW_Liaison bob = new CW_Liaison();
bob.Run("CW_Console", true);
}
```
5 Head back to `ConsoleCommands` and make it public.
6 Stay in `ConsoleCommands` and write the following line,
```c#
public static string Test()
{
return "Congratulations! It works.";
}
```
7 Run the program and type *"Test"* into the console.
8 If all has gone well, you should see the *“Congratulations! It works."* message.
9 Add more methods to you console program.
## Guides
There are several guides for Console.Waterworks and in various forms. I am hopeful you will find at least one of them helpful.
### Offline
I have created two guides for offline usage:
- The Quick Guide to Console.Waterworks
- The Complete Guide to Console.Waterworks
Both of these guides are printer friendly. And, they are best consumed on your favourite reading chair. If you are away from the world-wide web, these guides are, also, for you.
### Online
For those sitting at their computer and connected to the world-wide web, there is a Wiki:
- GitHub Wiki
This guide aims to be a concise as possible. It assumes you are sitting at your desk and wanting the quick answer -- not the full answer.
## Code of Conduct
Please visit the Code of Conduct page for Console.Waterworks at,
- Code of Conduct page
## Contributing to the Console.Waterworks Repository
Please visit the Contributing page for Console.Waterworks at,
- Contributing page
## About the Creator
Hi, my name is Craig and I'm the creator of Console.Waterworks. Thanks for checking it out.
- Email: craig@craigoates.net
- Web: http://www.craigoates.net
Loading…
Cancel
Save