Skip to content

Commit

Permalink
code cleaning; translate documentation; version 1.0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexSnowLeo committed Jul 16, 2019
1 parent 17141a3 commit 12e4a60
Show file tree
Hide file tree
Showing 12 changed files with 742 additions and 713 deletions.
77 changes: 39 additions & 38 deletions ConsoleConfiguration/CommandLineArgumentAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,47 @@

namespace SubrealTeam.Common.ConsoleConfiguration
{
/// <summary>
/// Атрибут определяющий конфигурационный параметр командной строки
/// </summary>
public class CommandLineArgumentAttribute : Attribute
{
/// <summary>
/// Создать аргумент конфигурации командной строки
/// </summary>
/// <param name="name">Наименование параметра командной строки</param>
/// <param name="parseTemplate">Шаблон значения атрибута. default: {name}={value}</param>
/// <param name="defaultValue">Значение по умолчанию. default: ""</param>
/// <param name="description">Описание параметра.</param>
public CommandLineArgumentAttribute(string name, string parseTemplate = "{name}={value}", object defaultValue = null, string description = "")
{
Name = name;
ParseTemplate = parseTemplate;
DefaultValue = defaultValue;
Description = description;
}
/// <summary>
/// Attribute defining command line configuration parameter
/// </summary>
public class CommandLineArgumentAttribute : Attribute
{
/// <summary>
/// Create command line configuration argument
/// </summary>
/// <param name="name">Command line parameter name</param>
/// <param name="parseTemplate">Attribute value template. default: {name}={value}</param>
/// <param name="defaultValue">Default value. default: ""</param>
/// <param name="description">Description of the parameter.</param>
public CommandLineArgumentAttribute(string name, string parseTemplate = "{name}={value}",
object defaultValue = null, string description = "")
{
Name = name;
ParseTemplate = parseTemplate;
DefaultValue = defaultValue;
Description = description;
}

/// <summary>
/// Наименование параметра командной строки
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Command line parameter name
/// </summary>
public string Name { get; }

/// <summary>
/// Шаблон значения атрибута
/// {name}={value} (по умолчанию).
/// Например: /{name}:{value}
/// </summary>
public string ParseTemplate { get; private set; }
/// <summary>
/// Attribute value template
/// {name}={value} (default).
/// For example: /{name}:{value}
/// </summary>
public string ParseTemplate { get; }

/// <summary>
/// Значение по умолчанию
/// </summary>
public object DefaultValue { get; set; }
/// <summary>
/// Default value
/// </summary>
public object DefaultValue { get; set; }

/// <summary>
/// Описание
/// </summary>
public string Description { get; set; }
}
/// <summary>
/// Description
/// </summary>
public string Description { get; set; }
}
}
248 changes: 121 additions & 127 deletions ConsoleConfiguration/ConsoleConfigurationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,146 +8,140 @@

namespace SubrealTeam.Common.ConsoleConfiguration
{
/// <summary>
/// Базовый класс конфигурации консольного приложения
/// </summary>
public abstract class ConsoleConfigurationBase
{
protected string[] _arguments;

/// <summary>
/// Аргументы командной строки
/// </summary>
public string[] Arguments => _arguments;

/// <summary>
/// Установить аргументы
/// </summary>
protected virtual void SetArguments()
{
_arguments = Environment.GetCommandLineArgs();
}

/// <summary>
/// Флаг - параметры не указаны
/// </summary>
public bool NoParameters => Arguments.Length == 1;

/// <summary>
/// Флаг ошибки считвания параметров
/// </summary>
public bool NotValidParameters => NotValidParamtersMessages.Any();

/// <summary>
/// Сообщения об ошибке считывания параметров
/// </summary>
public List<string> NotValidParamtersMessages { get; }
/// <summary>
/// Base class configuration of the console application
/// </summary>
public abstract class ConsoleConfigurationBase
{
/// <summary>
///
/// </summary>
protected string[] Arguments;

/// <summary>
/// Set arguments
/// </summary>
protected virtual void SetArguments()
{
Arguments = Environment.GetCommandLineArgs();
}

/// <summary>
/// Flag - no parameters specified
/// </summary>
public bool NoParameters => Arguments.Length == 1;

/// <summary>
/// Parameter read error flag
/// </summary>
public bool NotValidParameters => NotValidParametersMessages.Any();

/// <summary>
/// Parameters Read Error Messages
/// </summary>
public List<string> NotValidParametersMessages { get; }

/// <summary>
/// Кешь свойств класса с атрибутом командной строки
/// Cache class properties with command line attribute
/// </summary>
private AttributedPropertyInfo[] _attributedProps;
private readonly AttributedPropertyInfo[] _attributedProps;

/// <summary>
/// Конструктор конфигурации консольного приложения
/// Console Application Configuration constructor
/// </summary>
protected ConsoleConfigurationBase()
{
SetArguments();
{
SetArguments();

NotValidParamtersMessages = new List<string>();
NotValidParametersMessages = new List<string>();

// по всем публичным свойствам класса
var typeInfo = this.GetType();
var publicProps = typeInfo.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var typeInfo = this.GetType();
var publicProps = typeInfo.GetProperties(BindingFlags.Public | BindingFlags.Instance);

// взять свойства с атрибутом CommandLineArgument
_attributedProps = publicProps.Select(x => new {property = x, customAttributes = x.GetCustomAttributes()})
.Where(x => x.customAttributes.Any(y => y.GetType() == typeof(CommandLineArgumentAttribute)))
.Select(x => new AttributedPropertyInfo
{
PropertyInfo = x.property,
_attributedProps = publicProps.Select(x => new {property = x, customAttributes = x.GetCustomAttributes()})
.Where(x => x.customAttributes.Any(y => y.GetType() == typeof(CommandLineArgumentAttribute)))
.Select(x => new AttributedPropertyInfo
{
PropertyInfo = x.property,
Attributes = x.customAttributes.Select(a => a as CommandLineArgumentAttribute).ToArray()
})
.ToArray();

foreach (var prop in _attributedProps)
{
foreach (var attr in prop.Attributes)
{
SetPropertyValue(attr, prop.PropertyInfo);
}
}
}

private void SetPropertyValue(CommandLineArgumentAttribute cmdAttr, PropertyInfo propertyInfo)
{
if (cmdAttr.DefaultValue == null && propertyInfo.PropertyType.Name != "String")
cmdAttr.DefaultValue = Activator.CreateInstance(propertyInfo.PropertyType);

var cmdValue = Arguments.FirstOrDefault(x => x.ToUpper().StartsWith(cmdAttr.Name.ToUpper()));
// аргумент не указан, взять значение по умолчанию
if (String.IsNullOrWhiteSpace(cmdValue))
{
propertyInfo.SetValue(this, Convert.ChangeType(cmdAttr.DefaultValue, propertyInfo.PropertyType));
return;
}

var match = Regex.Match(cmdAttr.ParseTemplate, "{name}(.*){value}");
// неверно задан шаблон атрибута
if (!match.Success || match.Groups.Count <= 0)
{
var errorMessage =
$"Неверно задан шаблон атрибута {cmdAttr.ParseTemplate}, формат: {{имя}}{{разделитель}}{{значение}}";
NotValidParamtersMessages.Add(errorMessage);
Logger.Error(errorMessage);
return;
}

var splitter = match.Groups[1].Value;
var value = Regex.Split(cmdValue, splitter);

// указано значение атрибута, пробуем сконвертировать
object convertedValue;
try
{
if ((value.Length == 2) && !String.IsNullOrWhiteSpace(value[1]))
{
if (propertyInfo.PropertyType.Name == "Decimal")
{
value[1] = value[1].Replace(".", NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator)
.Replace(",", NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator);
}
convertedValue = Convert.ChangeType(value[1], propertyInfo.PropertyType);
}
else convertedValue = Convert.ChangeType(cmdAttr.DefaultValue, propertyInfo.PropertyType);
}
catch (FormatException e)
{
var errorMessage =
$"Ошибка конвертирования параметра \"{cmdValue}\", тип аргумента: \"{propertyInfo.PropertyType.Name}\"";
NotValidParamtersMessages.Add(errorMessage);
Logger.Error(errorMessage);
return;
}

propertyInfo.SetValue(this, convertedValue);
}

/// <summary>
/// Печать описания параметров с выводом в консоль
/// </summary>
/// <returns>флаг вывода в консоль</returns>
public string PrintHelp(bool printToConsole = true)
{
var helpMessage = String.Join(Environment.NewLine,
_attributedProps.SelectMany(a => a.Attributes.Select(x => $"{x.Name} - {x.Description}").ToArray()));

})
.ToArray();

foreach (var prop in _attributedProps)
{
foreach (var attr in prop.Attributes)
{
SetPropertyValue(attr, prop.PropertyInfo);
}
}
}

private void SetPropertyValue(CommandLineArgumentAttribute cmdAttr, PropertyInfo propertyInfo)
{
if (cmdAttr.DefaultValue == null && propertyInfo.PropertyType.Name != "String")
cmdAttr.DefaultValue = Activator.CreateInstance(propertyInfo.PropertyType);

var cmdValue = Arguments.FirstOrDefault(x => x.ToUpper().StartsWith(cmdAttr.Name.ToUpper()));
if (string.IsNullOrWhiteSpace(cmdValue))
{
propertyInfo.SetValue(this, Convert.ChangeType(cmdAttr.DefaultValue, propertyInfo.PropertyType));
return;
}

var match = Regex.Match(cmdAttr.ParseTemplate, "{name}(.*){value}");
if (!match.Success || match.Groups.Count <= 0)
{
var errorMessage =
$"Invalid attribute template {cmdAttr.ParseTemplate}, format: {{name}}{{delimiter}}{{value}}";
NotValidParametersMessages.Add(errorMessage);
Logger.Error(errorMessage);
return;
}

var splitter = match.Groups[1].Value;
var value = Regex.Split(cmdValue, splitter);

object convertedValue;
try
{
if ((value.Length == 2) && !string.IsNullOrWhiteSpace(value[1]))
{
if (propertyInfo.PropertyType.Name == "Decimal")
{
value[1] = value[1].Replace(".", NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator)
.Replace(",", NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator);
}

convertedValue = Convert.ChangeType(value[1], propertyInfo.PropertyType);
}
else convertedValue = Convert.ChangeType(cmdAttr.DefaultValue, propertyInfo.PropertyType);
}
catch (FormatException e)
{
var errorMessage =
$"Error converting parameter \"{cmdValue}\", argument type: \"{propertyInfo.PropertyType.Name}\"";
NotValidParametersMessages.Add(errorMessage);
Logger.Error(errorMessage);
return;
}

propertyInfo.SetValue(this, convertedValue);
}

/// <summary>
/// Printing parameter descriptions with console output
/// </summary>
/// <returns>Console output flag</returns>
public string PrintHelp(bool printToConsole = true)
{
var helpMessage = string.Join(Environment.NewLine,
_attributedProps.SelectMany(a => a.Attributes.Select(x => $"{x.Name} - {x.Description}").ToArray()));

if (printToConsole) Console.WriteLine(helpMessage);
return helpMessage;
}
return helpMessage;
}

}
}

internal class AttributedPropertyInfo
{
Expand Down
32 changes: 16 additions & 16 deletions Extensions/FileNameExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

namespace SubrealTeam.Common.Extensions
{
/// <summary>
/// Расширения для работы с именем файла
/// </summary>
public static class FileNameExtensions
{
/// <summary>
/// Добавить завершающий слешь к пути до файла
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string AddTrailingSlash(this string path)
{
if (path.IsEmpty()) return path;
/// <summary>
/// File Name Extensions
/// </summary>
public static class FileNameExtensions
{
/// <summary>
/// Add trailing to the file path
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string AddTrailingSlash(this string path)
{
if (path.IsEmpty()) return path;

return !path.EndsWith(Path.DirectorySeparatorChar.ToString()) ? path + Path.DirectorySeparatorChar : path;
}
}
return !path.EndsWith(Path.DirectorySeparatorChar.ToString()) ? path + Path.DirectorySeparatorChar : path;
}
}
}
Loading

0 comments on commit 12e4a60

Please sign in to comment.