Description
Have you built nice library and realized adding CLI tooling would be great but you get headache whenever thinking about all the wasted time on writing boilerplate code?
Are you going to create complex command line app and looking for structured, testable architecture?
Do you want to spin up CLI apps easily and quickly?
You may found the answer.
Jarilo alternatives and similar packages
Based on the "CLI" category.
Alternatively, view Jarilo alternatives based on common mentions on social networks and blogs.
-
spectre.console
A .NET library that makes it easier to create beautiful console applications. -
Command Line Parser
The best C# command line parser that brings standardized *nix getopt style, for .NET. Includes F# support -
Sieve
⚗️ Clean & extensible Sorting, Filtering, and Pagination for ASP.NET Core -
Console Framework
Cross-platform toolkit for easy development of TUI applications. -
Fluent Command Line Parser
A simple, strongly typed .NET C# command line parser library using a fluent easy to use interface -
CsConsoleFormat
.NET C# library for advanced formatting of console output [Apache] -
EntryPoint
Composable CLI Argument Parser for all modern .Net platforms. -
NFlags
Simple yet powerfull library to made parsing CLI arguments easy. Library also allow to print usage help "out of box". -
Appccelerate - Command Line Parser
A simple command line parser with fluent definition API. -
RunInfoBuilder
A unique command line parser for .NET that utilizes object trees for commands. -
Sitemap Tools
A sitemap (sitemap.xml) querying and parsing library for .NET -
Robots Exclusion Tools
A "robots.txt" parsing and querying library for .NET -
Tamar.ANSITerm
“ANSITerm” provides ANSI escape codes and true color formatting for .NET Core's Console on Linux terminals. -
DarkXaHTeP.CommandLine
Allows creating CommandLine applications using Microsoft.Extensions.CommandLineUtils together with DI, Configuration and Logging in a convenient way similar to AspNetCore Hosting
Tired of breaking your main and manually rebasing outdated pull requests?
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of Jarilo or a related project?
README
Jarilo
.NET Core 2.0 command line application framework.
Have you built nice library and realized adding CLI tooling would be great but you get headache whenever thinking about all the wasted time on writing boilerplate code?
Are you going to create complex command line app and looking for structured, testable architecture?
Do you want to spin up CLI apps easily and quickly?
You may found the answer.
Motivation:
I decided to take my CLI applications development to higher level. No more spaghetti-parsing code, no more hand-written documentation, no more unability to test my apps. The goal of this project is to develop smooth and easy workflow for creating CLI applications supporting good programming practices.
I share my work with community hoping that you can also benefit from it like I do. I'd also be really happy to see criticism and feedback from any of you.
Although I eventually picked up different approach, great inspiration for Jarilo project was this article: Creating Neat .NET Core Command Line Apps.
Overview:
Jarilo takes MVC approach where C stands for Command instead of Controller. This architecture lets build Jarilo apps from components which are highly decoupled and testable. Jarilo supports dependency injection and automatically generated documentation.
Usage:
Installation:
All released Jarilo versions can be obtained via NuGet Package Manager.
Package | Version | Build |
---|---|---|
Jarilo | 1.3.0 |
Running application:
Jarilo app can be run in just few lines of code:
static void Main(string[] args)
{
var app = new App();
app.Run(args);
}
The App
class takes care of building and running application. Where does all the logic go?
Commands:
Commands are entry points for user's requests. Command at its simplest form looks like this:
[Command("hello", "Greets user.")]
class Command
{
public void Run()
{
Console.WriteLine("Hello, user!");
}
}
Command line example:
> hello
Hello, user!
Arguments:
Commands can have arguments. Arguments are used by defining class with [Argument]
ed properties and injecting that class into command's Run()
method:
class Arguments
{
[Argument("User's name.")]
public string Name { get; set; }
}
[Command("hello", "Greets user.")]
class Command
{
public void Run(Arguments arguments)
{
var userName = string.IsNullOrEmpty(arguments.Name)
? "stranger"
: arguments.Name;
Console.WriteLine($"Hello, {userName}!");
}
}
> hello
Hello, stranger!
> hello Alice
Hello, Alice!
Options:
Commands can also have options. Using options is similar to using arguments:
class Options
{
[Option("--caring", "Ask user for mood after invitation.")]
public bool IsCaring { get; set; }
}
[Command("hello", "Greets user.")]
class Command
{
public void Run(Arguments arguments, Options options)
{
var userName = string.IsNullOrEmpty(arguments.Name)
? "stranger"
: arguments.Name;
Console.WriteLine($"Hello, {userName}!");
if (options.IsCaring)
{
Console.WriteLine("How are you today?");
}
}
}
> hello --caring
Hello, stranger!
How are you today?
> hello Alice --caring
Hello, Alice!
How are you today?
Parsing enums:
Enum types can be used both as arguments and options. In order to tell parser how map enum fields, enum should be defined like this:
enum Title
{
None,
[Value("sir", "Title for gentlemans.")]
Sir,
[Value("madame", "Title for ladies.")]
Madame
}
class Arguments
{
[Argument("User's title.")]
public Title Title { get; set; }
}
[Command("hello", "Greets user.")]
class Command
{
public void Run(Arguments arguments)
{
Console.WriteLine($"Hello, {arguments.Title}!");
}
}
> hello
Hello, Title.None!
> hello madame
Hello, Title.Madame!
Views:
Presentation layer can be decoupled from commands by introducing views. Take a look at implementation:
class View
{
public void Render()
{
Console.WriteLine("Hello, stranger!");
}
}
[Command("hello", "Greets user.")]
[View(typeof(View))]
class Command
{
public void Run()
{
}
}
> hello
Hello, stranger!
ViewModels:
Passing data from commands to views is handled by view models. View model is an object returned by command's Run()
method and passed to view's Render()
method:
class ViewModel
{
public string FormattedMessage { get; set; }
}
class View
{
public void Render(ViewModel viewModel)
{
Console.WriteLine(viewModel.FormattedMessage);
}
}
[Command("hello", "Greets user.")]
[View(typeof(View))]
class Command
{
public ViewModel Run()
{
var message = "Hello, stranger!";
return new ViewModel
{
FormattedMessage = $"** {message} **";
};
}
}
> hello
** Hello, stranger! **
Dependency injection:
Jarilo uses Microsoft.Extensions.DependencyInjection
as inversion of control container. It can be used to inject services into commands. Registering dependencies is straightforward:
class GreetingService : IGreetingService
{
public string Greet(string userName)
{
return $"Hello, {userName}!";
}
}
static void Main(string[] args)
{
var app = new App();
app.Services.AddSingleton<IGreetingService, GreetingService>();
app.Run(args);
}
[Command("hello", "Greets user.")]
class Command
{
readonly IGreetingService _greetingService;
public Command(IGreetingService greetingService)
{
_greetingService = greetingService;
}
public void Run()
{
var greeting = _greetingService.Greet("stranger");
Console.WriteLine(greeting);
}
}
> hello
Hello, stranger!
Read-Eval-Print Loop (REPL)
Jarilo supports alternative run mode - REPL. It allows users for interactive sessions with the app. Jarilo app can be run in REPL mode like that:
static void Main()
{
var app = new App();
app.ReadEvalPrintLoop();
}
Documentation
Jarilo handles special help options -?
-h
--help
which can be used with any command to print auto-generated documentation. The documentation is based on application's structure and on metadata provided in attributes.
enum Title
{
None,
[Value("sir", "Title for gentlemans.")]
Sir,
[Value("madame", "Title for ladies.")]
Madame
}
class Arguments
{
[Argument("User's name.")]
public string Name { get; set; }
}
class Options
{
[Option("--caring", "Ask user for mood after invitation.")]
public bool IsCaring { get; set; }
[Option("--title", "User's title.")]
public Title Title { get; set; }
}
[Command("hello", "Greets user.")]
class Command
{
public void Run(Arguments arguments, Options options)
{
// handle command...
}
}
> --help
Usage:
<command> [arguments] [options]
Commands:
hello
> hello --help
Command:
Greets user.
Usage:
hello <name> [options]
Arguments:
<name> - User's name.
Options:
--caring - Ask user for mood after invitation.
--title <value> - User's title.
Possible values:
sir - Title for gentlemans.
madame - Title for ladies.
Style guide and recommendations:
Please check project Jarilo.Examples
in source code for more sophisticated examples and my preferred directory per feature
way of structuring Jarilo applications.
Lacking features:
async
support.- Shorthand options.
- Setting return code of an app.
- Exporting documentation of application (e. g. in Markdown format).
- Rich configuration options (e.g. translations, REPL prompt etc).
- Pluggable IoC container.
- Some kind of view template engine - that could be really nice feature.
- Docs and examples of testing Jarilo apps.
- Reactive views.
Got anything on your mind? I'd feel happy to see you contribute or file an issue.