• Stars
    star
    134
  • Rank 261,788 (Top 6 %)
  • Language
    Crystal
  • License
    MIT License
  • Created over 7 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A robust DSL for writing command line interfaces written in Crystal.

Admiral.cr

Build Status Crystal Docs

⭐ Work's with Crystal 1.0.0 and with support back to 0.34.0

A robust DSL for writing command line interfaces written in Crystal.


Installation | Usage | Examples | Contributing | In the Wild

Installation

Add the following to your application's shard.yml file.

dependencies:
  admiral:
    github: jwaldrip/admiral.cr

Usage

Creating a new CLI | Flags | Arguments | Sub Commands | Command Help | Command Version

Creating a new CLI

You can define a CLI by creating a new class that inherits from Admiral::Command. All your class needs to implement is a run method. Inside the run method will be the logic of your cli application. The following is a very basic CLI. You can run the command by invoking HelloWorld.run. By default this method will use ARGV, but you can also pass Array(String) or String.

# hello_world.cr
require "admiral"

class HelloWorld < Admiral::Command
  def run
    puts "Hello World"
  end
end

HelloWorld.run
$ crystal run ./hello_world.cr
Hello World

Flags

Flags can be added to the command. To define a flag use the define_flag macro.

Note: When defining flags, the underscore method name will translate to a hyphen on the command line. This can be overridden with the long: my_name option when defining the flag.

Simple Flags

Simple flags are denoted only by a name and will compile to returning a String | Nil.

# hello_world.cr
class HelloWorld < Admiral::Command
  define_flag planet

  def run
    puts "Hello #{flags.planet || "World"}"
  end
end

HelloWorld.run
$ crystal build ./hello_world.cr
$ ./hello_world
Hello World
$ ./hello_world --planet Alderaan
Hello Alderaan

Typed Flags

Flags can also be assigned a type. This will result in a properly typed value when calling flags.flag_name. By default flags are not required and will return a Union including the type and Nil.

# hello_world.cr
class HelloWorld < Admiral::Command
  define_flag number_of_greetings : UInt32, default: 1_u32, long: times

  def run
    flags.times.times do
      puts "Hello World"
    end
  end
end

HelloWorld.run
$ crystal build ./hello_world.cr
$ ./hello_world  --times 3
Hello World
Hello World
Hello World

Built in flag types

The following classes are assignable as flags by default:

  • String
  • Bool
  • Float32
  • Float64
  • Int8
  • Int16
  • Int32
  • Int64
  • UInt8
  • UInt16
  • UInt32
  • UInt64

Pro Tip
To make any Class or Struct assignable as a flag, define a .new(value : ::Admiral::StringValue) or
#initialize(value : ::Admiral::StringValue).

Enumerable Flags

Enumerable flags allow for multiple values to be passed on the command line. For example with a defined flag with Array(String) would return an array of String values when calling the flag.

# hello_world.cr
class HelloWorld < Admiral::Command
  define_flag citizens : Array(String), long: citizen

  def run
    flags.citizen.each do |citizen|
      puts "Hello #{citizen}, citizen of Earth!"
    end
  end
end

HelloWorld.run
$ crystal build ./hello_world.cr
$ ./hello_world  --citizen Jim --citizen Harry
Hello Jim, citizen of Earth!
Hello Harry, citizen of Earth!

Additional Flag Options

# hello_world.cr
class HelloWorld < Admiral::Command
  define_flag number_of_greetings : UInt32,
              description: "The number of times to greet the world",
              default: 1_u32,
              long: times,
              short: t,
              required: true

  def run
    flags.number_of_greetings.times do
      puts "Hello World"
    end
  end
end

HelloWorld.run
Option Description
description The description of the flag to be used in auto generated help.
default The default value of the flag.
long The long version of the flag ex: long: times for --times.
short The short version of the flag ex: short: t for -t.
required Denotes if a flag is required. Required flags without a default value will raise an error when not specified at command invocation.

Arguments

Arguments can be added to the command. To define a argument use the define_argument macro.

Simple Arguments

Simple arguments are denoted only by a name and will compile to returning a String | Nil.

# hello.cr
class Hello < Admiral::Command
  define_argument planet

  def run
    puts "Hello #{arguments.planet || "World"}"
  end
end

HelloWorld.run
$ crystal build ./world.cr
$ ./hello
Hello World
$ ./hello Alderaan
Hello Alderaan

Typed Arguments

Arguments can also be assigned a type. This will result in a properly typed value when calling arguments.arg_name. By default arguments are not required and will return a Union including the type and Nil.

# hello_world.cr
class HelloWorld < Admiral::Command
  define_argument number_of_greetings : UInt32, default: 1_u32

  def run
    arguments.number_of_greetings.times do
      puts "Hello World"
    end
  end
end

HelloWorld.run
$ crystal build ./hello_world.cr
$ ./hello_world  3
Hello World
Hello World
Hello World

Built in argument types

The following classes are assignable as arguments by default:

  • String
  • Bool
  • Float32
  • Float64
  • Int8
  • Int16
  • Int32
  • Int64
  • UInt8
  • UInt16
  • UInt32
  • UInt64

Pro Tip
To make any Class or Struct assignable as a argument, define a .new(value : ::Admiral::StringValue) or
#initialize(value : ::Admiral::StringValue).

Additional Argument Options

# hello_world.cr
class HelloWorld < Admiral::Command
  define_argument number_of_greetings : UInt32,
                  description: "The number of times to greet the world",
                  default: 1_u32,
                  required: true

  def run
    arguments.number_of_greetings.times do
      puts "Hello World"
    end
  end
end

HelloWorld.run
Option Description
description The description of the argument to be used in auto generated help.
default The default value of the argument.
required Denotes if a argument is required. Required arguments without a default value will raise an error when not specified at command invocation.

Note:
Required arguments cannot be defined after optional arguments.

Sub Commands

Sub commands can be added to the command. To define a sub command use the register_sub_command macro. You also have the option to add a description for the auto-generated help.

# hello.cr
class Hello < Admiral::Command
  class Planetary < Admiral::Command
    def run
      puts "Hello World"
    end
  end

  class Municipality < Admiral::Command
    def run
      puts "Hello Denver"
    end
  end

  register_sub_command planet : Planetary
  register_sub_command city : Municipality

  def run
    puts help
  end
end

HelloWorld.run
$ crystal build ./hello.cr
$ ./hello planet
Hello World
$ ./hello city
Hello Denver

Command Help

Auto-generated Help

You can add a help command to your CLI by using the define_help macro. define_help also takes a description argument to give additional information about your command.

# hello.cr
class Hello < Admiral::Command
  define_help description: "A command that says hello"
  define_argument planet, default: "World"

  def run
    puts "Hello #{arguments.planet}"
  end
end
$ crystal build ./hello.cr
$ ./hello --help
Usage:
  ./hello [flags...] <planet> [arg...]

A command that says hello

Flags:
  --help

Arguments:
  planet (default: World)

Custom Help

You can also generate your own custom help text.

# hello.cr
class Hello < Admiral::Command
  define_help custom: "This is the help for my command"

  def run
  end
end

Command Version

Like most CLI applications, you can set a version flag.

# hello.cr
class Hello < Admiral::Command
  define_version "1.0.0"

  def run
  end
end
$ crystal build ./hello.cr
$ hello --version
1.0.0

Examples

Example CLIs can be found in ./examples

In the wild

Here are some tools using Admiral.cr in the wild. Have your own you would like to plug? Submit a pull request!

Todo

  • Basic Flags
  • Typed Flags
  • Boolean Flags
  • Enum Flags
  • Named Arguments
  • Positional Arguments
  • Sub Commands
  • Documentation
  • Fully Tested
  • Bash Completion
  • Zsh Completion

Contributing

See CONTRIBUTING for details on how to contribute.

More Repositories

1

odin

A go-lang library to help build self documenting command line applications.
Go
246
star
2

terraform-coreos-user-data

CoreOS cloud config generation via Terraform variables
HCL
46
star
3

promise.cr

A Promise Implementation in Crystal
Crystal
32
star
4

git-get

Git clone that clones into a common path
Go
15
star
5

mime-types-cr

MIME Types for Crystal :: A port of the Ruby MIME::Types library
Crystal
10
star
6

shell-table.cr

Crystal
10
star
7

flatrack

A static site generator with a little sprinkle of ruby magic
Ruby
9
star
8

react-infinite-pane

Responsive infinite scroll pane for React
JavaScript
6
star
9

dotfiles

Jason Waldrip's Dev Environment
Makefile
6
star
10

crystal-sf2017

Crystal
6
star
11

stripe_rails

Ruby
5
star
12

tint

Go
3
star
13

http_cache_handler

Crystal
3
star
14

jasonwaldrip.com

My Little Website
CSS
3
star
15

graphql.cr

An implementation of GraphQL for Crystal
Crystal
3
star
16

of

A simple gem to give you n number of objects.
Ruby
3
star
17

workman

Define and run parallel workers in go
Go
2
star
18

navigable_hash

Ruby
2
star
19

modloc

Find the source location of a given module or class
Ruby
2
star
20

memory_model

A familar model construct that lives only when your app is running (Great for RSpec!)
Ruby
2
star
21

libgraphql-cr

Crystal
2
star
22

delegated_presenter

DelegatedPresenter, More info on rubydoc.info:
Ruby
1
star
23

docker-ruby-app

Shell
1
star
24

docker-mysql

Shell
1
star
25

docker-rails-app

Shell
1
star
26

docker-mariadb

Shell
1
star
27

faxfinder-override

CSS
1
star
28

docker-base

Shell
1
star
29

relay-vote

A voting app in relay.
JavaScript
1
star
30

docker-host

Ruby
1
star
31

docker-node

Shell
1
star
32

docker-rbenv

Shell
1
star
33

modernize-hashes

Ruby
1
star
34

jwaldrip.github.com

1
star
35

def_cache

Ruby
1
star
36

git-cleanremote

Clean up your remote repos
Ruby
1
star
37

node-docker-example

JavaScript
1
star
38

docker-docker

Shell
1
star
39

all_the_badges

Ruby
1
star
40

carly-paige

JavaScript
1
star
41

docker-railsdev

A feature full rails development environment.
1
star
42

concerned_inheritance

Ruby
1
star
43

pollr

Ruby
1
star
44

12f-elasticsearch

12 Factor Configurable Elasticsearch
Makefile
1
star
45

sinful-proxy

A Simple Proxy Written in Sinatra
Ruby
1
star
46

keep-em-up

Ruby
1
star
47

haml-flatrack

Ruby
1
star
48

homebrew-on-tap

Ruby
1
star
49

slim-flatrack

Slim for flatrack
1
star
50

12f-vault

Shell
1
star
51

tar.cr

Tape archives (tar) are a file format for storing a sequence of files that can be read and written in a streaming manner. This package aims to cover most variations of the format, including those produced by GNU and BSD tar tools.
Crystal
1
star