Skip to content

Commit

Permalink
Merge pull request #207 from adambajguz/feature/issue-186_dynamic-com…
Browse files Browse the repository at this point in the history
…mands

Feature/issue 186 dynamic commands
  • Loading branch information
adambajguz authored Jul 13, 2021
2 parents e1bc800 + f928335 commit 6d159d9
Show file tree
Hide file tree
Showing 239 changed files with 4,646 additions and 1,506 deletions.
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
### v3.1.0 (xx-Apr-2021)
### v4.0.0 (xx-Jul-2021)

- Added dynamic commands support.
- Replaced `ICommand.ExecuteAsync(CancellationToken cancellationToken)` with `IConsole.ExecuteAsync(CancellationToken cancellationToken)`.
- Renamed `CommandParameterAttribute` to `ParameterAttribute`.
- Renamed `CommandOptionAttribute` to `OptionAttribute`.
- Renamed `CommandOptionSchema` to `OptionSchema`.
- Renamed `CommandParameterSchema` to `ParameterSchema`.

- Added `InteractiveModeOptions.Prompt`, `InteractiveModeOptions.SetDefaultPrompt()` and `InteractiveModeOptions.SetPrompt()` for specifying custom prompt template. `PromptForeground` and `ScopeForeground` can still be used to configure foreground without changing prompt template.
- Added `BindableProperyInfo` and `ArgumentSchema.BindableProperty`, as well as marked `ArgumentSchema.Property`, `ArgumentSchema.IsScalar`, and `ArgumentSchema.GetValidValues()` obsolete - will be removed in Typin 4.0.
- Added `BindableArgument` and `ArgumentSchema.Bindable`.
- Removed `ArgumentSchema.Property`, `ArgumentSchema.IsScalar`, and `ArgumentSchema.GetValidValues()`.
- Removed `IDisposable` from `CliContext`.
- Faster `Guid` binding by explicit `Guid.Parse()` call (added `Guid` to `ArgumentBinder.PrimitiveConverters`).
- Changed default values format in help - now in round brackets.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
namespace Typin.Benchmarks.FrameworksComparison.Commands
{
using System.Threading;
using System.Threading.Tasks;
using Typin.Attributes;
using Typin.Console;

[Command]
public class TypinCommand : ICommand
{
[CommandOption("str", 's')]
[Option("str", 's')]
public string? StrOption { get; set; }

[CommandOption("int", 'i')]
[Option("int", 'i')]
public int IntOption { get; set; }

[CommandOption("bool", 'b')]
[Option("bool", 'b')]
public bool BoolOption { get; set; }

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
return default;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
namespace Typin.Benchmarks.MultiCommand.TypinCommands
{
using System.Threading;
using System.Threading.Tasks;
using Typin.Attributes;
using Typin.Console;

public abstract class TypinBaseCommand : ICommand
{
[CommandOption("str", 's')]
[Option("str", 's')]
public string? StrOption { get; set; }

[CommandOption("int", 'i')]
[Option("int", 'i')]
public int IntOption { get; set; }

[CommandOption("bool", 'b')]
[Option("bool", 'b')]
public bool BoolOption { get; set; }

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
return default;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Typin/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="all" />
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
<PackageReference Include="IsExternalInit" Version="1.0.0" PrivateAssets="all" />
<PackageReference Include="IsExternalInit" Version="1.0.1" PrivateAssets="all" />
</ItemGroup>

</Project>
21 changes: 12 additions & 9 deletions src/Typin/Examples/BookLibraryExample/Commands/BookAddCommand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace BookLibraryExample.Commands
{
using System;
using System.Threading;
using System.Threading.Tasks;
using BookLibraryExample.Internal;
using BookLibraryExample.Models;
Expand All @@ -15,25 +16,27 @@
public class BookAddCommand : ICommand
{
private readonly LibraryService _libraryService;
private readonly IConsole _console;

[CommandParameter(0, Name = "title", Description = "Book title.")]
[Parameter(0, Name = "title", Description = "Book title.")]
public string Title { get; init; } = "";

[CommandOption("author", 'a', IsRequired = true, Description = "Book author.")]
[Option("author", 'a', IsRequired = true, Description = "Book author.")]
public string Author { get; init; } = "";

[CommandOption("published", 'p', Description = "Book publish date.")]
[Option("published", 'p', Description = "Book publish date.")]
public DateTimeOffset Published { get; init; } = CreateRandomDate();

[CommandOption("isbn", 'n', Description = "Book ISBN.")]
[Option("isbn", 'n', Description = "Book ISBN.")]
public Isbn Isbn { get; init; } = CreateRandomIsbn();

public BookAddCommand(LibraryService libraryService)
public BookAddCommand(LibraryService libraryService, IConsole console)
{
_libraryService = libraryService;
_console = console;
}

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
if (_libraryService.GetBook(Title) is not null)
{
Expand All @@ -43,14 +46,14 @@ public ValueTask ExecuteAsync(IConsole console)
Book book = new(Title, Author, Published, Isbn);
_libraryService.AddBook(book);

console.Output.WriteLine("Book added.");
console.RenderBook(book);
_console.Output.WriteLine("Book added.");
_console.RenderBook(book);

return default;
}

#region Helpers
private static readonly Random Random = new Random();
private static readonly Random Random = new();

private static DateTimeOffset CreateRandomDate()
{
Expand Down
11 changes: 7 additions & 4 deletions src/Typin/Examples/BookLibraryExample/Commands/BookCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace BookLibraryExample.Commands
{
using System.Threading;
using System.Threading.Tasks;
using BookLibraryExample.Internal;
using BookLibraryExample.Models;
Expand All @@ -14,22 +15,24 @@
public class BookCommand : ICommand
{
private readonly LibraryService _libraryService;
private readonly IConsole _console;

[CommandParameter(0, Name = "title", Description = "Book title.")]
[Parameter(0, Name = "title", Description = "Book title.")]
public string Title { get; init; } = "";

public BookCommand(LibraryService libraryService)
public BookCommand(LibraryService libraryService, IConsole console)
{
_libraryService = libraryService;
_console = console;
}

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
Book? book = _libraryService.GetBook(Title);

_ = book ?? throw new CommandException("Book not found.", 1);

console.RenderBook(book);
_console.RenderBook(book);

return default;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace BookLibraryExample.Commands
{
using System;
using System.Threading;
using System.Threading.Tasks;
using BookLibraryExample.Internal;
using BookLibraryExample.Models;
Expand All @@ -13,13 +14,15 @@
public class BookListCommand : ICommand
{
private readonly LibraryService _libraryService;
private readonly IConsole _console;

public BookListCommand(LibraryService libraryService)
public BookListCommand(LibraryService libraryService, IConsole console)
{
_libraryService = libraryService;
_console = console;
}

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
Library library = _libraryService.GetLibrary();

Expand All @@ -29,18 +32,18 @@ public ValueTask ExecuteAsync(IConsole console)
// Margin
if (!isFirst)
{
console.Output.WriteLine();
_console.Output.WriteLine();
}

isFirst = false;

// Render book
console.RenderBook(book);
_console.RenderBook(book);
}

if (isFirst)
{
console.Output.WithForegroundColor(ConsoleColor.Red, (output) => output.WriteLine("No books"));
_console.Output.WithForegroundColor(ConsoleColor.Red, (output) => output.WriteLine("No books"));
}

return default;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace BookLibraryExample.Commands
{
using System.Threading;
using System.Threading.Tasks;
using BookLibraryExample.Models;
using BookLibraryExample.Services;
Expand All @@ -12,24 +13,26 @@
public class BookRemoveCommand : ICommand
{
private readonly LibraryService _libraryService;
private readonly IConsole _console;

[CommandParameter(0, Name = "title", Description = "Book title.")]
[Parameter(0, Name = "title", Description = "Book title.")]
public string Title { get; init; } = "";

public BookRemoveCommand(LibraryService libraryService)
public BookRemoveCommand(LibraryService libraryService, IConsole console)
{
_libraryService = libraryService;
_console = console;
}

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
Book? book = _libraryService.GetBook(Title);

_ = book ?? throw new CommandException("Book not found.", 1);

_libraryService.RemoveBook(book);

console.Output.WriteLine($"Book {Title} removed.");
_console.Output.WriteLine($"Book {Title} removed.");

return default;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
namespace InteractiveModeExample.Commands
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Typin;
using Typin.Attributes;
using Typin.Console;
using Typin.DynamicCommands;
using Typin.Metadata;
using Typin.Schemas;

[Command("add dynamic", Description = "Adds a dynamic command.")]
public class AddDynamicCommand : ICommand
{
private readonly IConsole _console;
private readonly IDynamicCommandBuilderFactory _dynamicCommandBuilderFactory;
private readonly RootSchema _rootSchema;

[Option("name")]
public string Name { get; init; } = string.Empty;

public AddDynamicCommand(IConsole console, IDynamicCommandBuilderFactory dynamicCommandBuilderFactory, IRootSchemaAccessor rootSchemaAccessor)
{
_console = console;
_dynamicCommandBuilderFactory = dynamicCommandBuilderFactory;
_rootSchema = rootSchemaAccessor.RootSchema;
}

public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
CommandSchema commandSchema = _dynamicCommandBuilderFactory.Create<SampleDynamicCommand>(Name)
.WithDescription("Test description.")
.WithManual("Some manual\nadd dynamic --name abc\nabc 5 j --number 4 -a aaaaaa\nabc --help.")
.AddOption<int>("Number", (ob) => ob
.AsRequired()
.WithDescription("Some number.")
.SetMetadata(new ArgumentMetadata("test"))
)
.AddOption(typeof(double))
.AddOption<int>((ob) => ob
.SetMetadata(new ArgumentMetadata("test"))
)
.AddOption<string>("Str")
.AddOption(typeof(double), "Price")
.AddParameter<string>("Parameter", 0)
.AddParameter<string>(1)
.Build();

if (_rootSchema.TryAddDynamicCommand(commandSchema))
{
_console.Output.WithForegroundColor(ConsoleColor.Green, (err) => err.WriteLine($"Successfully added dynamic command '{Name}'."));
}
else
{
_console.Error.WithForegroundColor(ConsoleColor.Red, (err) => err.WriteLine($"Failed to add dynamic command '{Name}'."));
}

return default;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace InteractiveModeExample.Commands
{
using System;
using System.Threading;
using System.Threading.Tasks;
using InteractiveModeExample.Internal;
using InteractiveModeExample.Models;
Expand All @@ -15,25 +16,27 @@
public class BookAddCommand : ICommand
{
private readonly LibraryService _libraryService;
private readonly IConsole _console;

[CommandParameter(0, Name = "title", Description = "Book title.")]
[Parameter(0, Name = "title", Description = "Book title.")]
public string Title { get; init; } = "";

[CommandOption("author", 'a', IsRequired = true, Description = "Book author.")]
[Option("author", 'a', IsRequired = true, Description = "Book author.")]
public string Author { get; init; } = "";

[CommandOption("published", 'p', Description = "Book publish date.")]
[Option("published", 'p', Description = "Book publish date.")]
public DateTimeOffset Published { get; init; } = CreateRandomDate();

[CommandOption("isbn", 'n', Description = "Book ISBN.")]
[Option("isbn", 'n', Description = "Book ISBN.")]
public Isbn Isbn { get; init; } = CreateRandomIsbn();

public BookAddCommand(LibraryService libraryService)
public BookAddCommand(LibraryService libraryService, IConsole console)
{
_libraryService = libraryService;
_console = console;
}

public ValueTask ExecuteAsync(IConsole console)
public ValueTask ExecuteAsync(CancellationToken cancellationToken)
{
if (_libraryService.GetBook(Title) is not null)
{
Expand All @@ -43,14 +46,14 @@ public ValueTask ExecuteAsync(IConsole console)
Book book = new(Title, Author, Published, Isbn);
_libraryService.AddBook(book);

console.Output.WriteLine("Book added.");
console.RenderBook(book);
_console.Output.WriteLine("Book added.");
_console.RenderBook(book);

return default;
}

#region Helpers
private static readonly Random Random = new Random();
private static readonly Random Random = new();

private static DateTimeOffset CreateRandomDate()
{
Expand Down
Loading

0 comments on commit 6d159d9

Please sign in to comment.