Slim command line interface builder for Crystal.
Crystal Makefile
Clone or download
Permalink
Failed to load latest commit information.
.vscode fix Mar 19, 2018
spec ... Jul 7, 2018
src version up Jul 7, 2018
.gitignore add .vscode dir Nov 25, 2017
.travis.yml pass Mar 16, 2018
LICENSE first commit Mar 29, 2017
Makefile spec Apr 28, 2018
README.md version up Jul 7, 2018
shard.yml version up Jul 7, 2018

README.md

clim

"clim" is slim command line interface builder for Crystal.

"clim" = "cli" + "slim"

Build Status

Goals

  • Slim implementation.
  • Intuitive code.

Support

  • Option types
    • Int8
    • Int16
    • Int32
    • Int64
    • UInt8
    • UInt16
    • UInt32
    • UInt64
    • Float32
    • Float64
    • String
    • Bool
    • Array(Int8)
    • Array(Int16)
    • Array(Int32)
    • Array(Int64)
    • Array(UInt8)
    • Array(UInt16)
    • Array(UInt32)
    • Array(UInt64)
    • Array(Float32)
    • Array(Float64)
    • Array(String)
  • Default values for option
  • Required flag for option
  • Nested sub commands
  • --help option
  • Customizable help message
  • version macro
  • Command name alias

Installation

Add this to your application's shard.yml:

dependencies:
  clim:
    github: at-grandpa/clim
    version: 0.4.0

Minimum sample

src/minimum.cr

require "clim"

class MyCli < Clim
  main_command do
    run do |options, arguments|
      puts "#{arguments.join(", ")}!"
    end
  end
end

MyCli.start(ARGV)
$ crystal build -o ./minimum src/minimum.cr
$ ./minimum foo bar baz
foo, bar, baz!

Command information sample

src/hello.cr

require "clim"

module Hello
  class Cli < Clim
    main_command do
      desc "Hello CLI tool."
      usage "hello [options] [arguments] ..."
      version "Version 0.1.0"
      option "-g WORDS", "--greeting=WORDS", type: String,        desc: "Words of greetings.", default: "Hello"
      option "-n NAME",  "--name=NAME",      type: Array(String), desc: "Target name.",        default: ["Taro"]
      run do |options, arguments|
        print "#{options.greeting}, "
        print "#{options.name.join(", ")}!"
        print "\n"
      end
    end
  end
end

Hello::Cli.start(ARGV)
$ crystal build src/hello.cr
$ ./hello --help

  Hello CLI tool.

  Usage:

    hello [options] [arguments] ...

  Options:

    -g WORDS, --greeting=WORDS       Words of greetings. [type:String] [default:"Hello"]
    -n NAME, --name=NAME             Target name. [type:Array(String)] [default:["Taro"]]
    --help                           Show this help.
    --version                        Show version.

$ ./hello -n Ichiro -n Miko -g 'Good night'
Good night, Ichiro, Miko!

Sub commands sample

src/fake-crystal-command.cr

require "clim"

module FakeCrystalCommand
  class Cli < Clim
    main_command do
      desc "Fake Crystal command."
      usage "fcrystal [sub_command] [arguments]"
      run do |options, arguments|
        puts options.help # => help string.
      end
      sub_command "tool" do
        desc "run a tool"
        usage "fcrystal tool [tool] [arguments]"
        run do |options, arguments|
          puts "Fake Crystal tool!!"
        end
        sub_command "format" do
          desc "format project, directories and/or files"
          usage "fcrystal tool format [options] [file or directory]"
          run do |options, arguments|
            puts "Fake Crystal tool format!!"
          end
        end
      end
      sub_command "spec" do
        desc "build and run specs"
        usage "fcrystal spec [options] [files]"
        run do |options, arguments|
          puts "Fake Crystal spec!!"
        end
      end
    end
  end
end

FakeCrystalCommand::Cli.start(ARGV)

Build and run.

$ crystal build -o ./fcrystal src/fake-crystal-command.cr
$ ./fcrystal

  Fake Crystal command.

  Usage:

    fcrystal [sub_command] [arguments]

  Options:

    --help                           Show this help.

  Sub Commands:

    tool   run a tool
    spec   build and run specs

Show sub command help.

$ ./fcrystal tool --help

  run a tool

  Usage:

    fcrystal tool [tool] [arguments]

  Options:

    --help                           Show this help.

  Sub Commands:

    format   format project, directories and/or files

Run sub sub command.

$ ./fcrystal tool format
Fake Crystal tool format!!

Usage

require & inherit

require "clim"

class MyCli < Clim

  # ...

end

Command Informations

desc

Description of the command. It is displayed in Help.

class MyCli < Clim
  main_command do
    desc "My Command Line Interface."
    run do |options, arguments|
      # ...
    end
  end
end

usage

Usage of the command. It is displayed in Help.

class MyCli < Clim
  main_command do
    usage  "mycli [sub-command] [options] ..."
    run do |options, arguments|
      # ...
    end
  end
end

alias_name

An alias for the command. It can be specified only for subcommand.

class MyCli < Clim
  main_command do
    run do |options, arguments|
      # ...
    end
    sub_command "sub" do
      alias_name  "alias1", "alias2"
      run do |options, arguments|
        puts "sub_command run!!"
      end
    end
  end
end
$ ./mycli sub
sub_command run!!
$ ./mycli alias1
sub_command run!!
$ ./mycli alias2
sub_command run!!

version

You can specify the string to be displayed with --version.

class MyCli < Clim
  main_command do
    version "mycli version: 1.0.1"
    run do |options, arguments|
      # ...
    end
  end
end
$ ./mycli --version
mycli version: 1.0.1

If you want to display it even with -v, add short: "-v".

class MyCli < Clim
  main_command do
    version "mycli version: 1.0.1", short: "-v"
    run do |options, arguments|
      # ...
    end
  end
end
$ ./mycli --version
mycli version: 1.0.1
$ ./mycli -v
mycli version: 1.0.1

option

You can specify multiple options for the command.

Argument Description Example Required Default
First argument short or long name -t TIMES, --times TIMES true -
Second argument long name --times TIMES false -
type option type type: Array(Float32) false String
desc option description desc: "option description." false "Option description."
default default value default: [1.1_f32, 2.2_f32] false nil
required required flag required: true false false
class MyCli < Clim
  main_command do
    option "--greeting=WORDS", desc: "Words of greetings.", default: "Hello"
    option "-n NAME", "--name=NAME", type: Array(String), desc: "Target name.", default: ["Taro"]
    run do |options, arguments|
      puts typeof(options.greeting) # => String
      puts typeof(options.name)     # => Array(String)
    end
  end
end

The type of the option is determined by the default and required patterns.

Number

For example Int8.

default required Type
exist true Int8 (default: Your specified value.)
exist false Int8 (default: Your specified value.)
not exist true Int8
not exist false Int8 | Nil

String

default required Type
exist true String (default: Your specified value.)
exist false String (default: Your specified value.)
not exist true String
not exist false String | Nil

Bool

default required Type
exist true Bool (default: Your specified value.)
exist false Bool (default: Your specified value.)
not exist true Bool
not exist false Bool (default: false)

Array

default required Type
exist true Array(T) (default: Your specified value.)
exist false Array(T) (default: Your specified value.)
not exist true Array(T)
not exist false Array(T) (default: [] of T)

For Bool, you do not need to specify arguments for short or long.

class MyCli < Clim
  main_command do
    option "-v", "--verbose", type: Bool, desc: "Verbose."
    run do |options, arguments|
      puts typeof(options.verbose) # => Bool
    end
  end
end

Option method names are long name if there is a long, and short name if there is only a short. Also, hyphens are replaced by underscores.

class MyCli < Clim
  main_command do
    option "-n", type: String, desc: "name."  # => short name only.
    option "--my-age", type: Int32, desc: "age." # => long name only.
    run do |options, arguments|
      puts typeof(options.n)      # => (String | Nil)
      puts typeof(options.my_age) # => (Int32 | Nil)
    end
  end
end

help_template

You can customize the help message. The help_template block must be placed before main_command. Also it needs to return String. Block arguments are desc : String, usage : String, options_help : String and sub_commands_help : String.

class MyCli < Clim
  help_template do |desc, usage, options_help, sub_commands_help|
    <<-MY_HELP

      command description: #{desc}
      command usage:       #{usage}

      options:
    #{options_help}

      sub_commands:
    #{sub_commands_help}


    MY_HELP
  end
  main_command do
    desc "foo command."
    usage "foo [options] [arguments]"
    option "--site=SITE", type: String, desc: "Site URL."
    run do |opts, args|
    end
    sub_command "sub_command" do
      desc "this is sub_comand."
      option "-n NUM", type: Int32, desc: "Number.", default: 0
      run do |opts, args|
      end
    end
  end
end
$ crystal run src/help_template_test.cr -- --help

  command description: foo command.
  command usage:       foo [options] [arguments]

  options:
    --site=SITE                      Site URL. [type:String]
    --help                           Show this help.

  sub_commands:
    sub_command   this is sub_comand.

help string

class MyCli < Clim
  main_command do
    run do |options, arguments|
      options.help # => help string
    end
  end
end

Development

$ make spec

Contributing

  1. Fork it ( https://github.com/at-grandpa/clim/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors