{"id":13482561,"url":"https://github.com/at-grandpa/clim","last_synced_at":"2025-04-15T06:05:20.151Z","repository":{"id":52978371,"uuid":"86608385","full_name":"at-grandpa/clim","owner":"at-grandpa","description":"Slim command line interface builder for Crystal.","archived":false,"fork":false,"pushed_at":"2021-04-11T14:35:21.000Z","size":832,"stargazers_count":123,"open_issues_count":1,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-15T06:05:12.045Z","etag":null,"topics":["clim","command-line-interface-builder","crystal"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/at-grandpa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-29T17:04:43.000Z","updated_at":"2024-11-29T11:42:57.000Z","dependencies_parsed_at":"2022-08-30T23:41:24.033Z","dependency_job_id":null,"html_url":"https://github.com/at-grandpa/clim","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at-grandpa%2Fclim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at-grandpa%2Fclim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at-grandpa%2Fclim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/at-grandpa%2Fclim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/at-grandpa","download_url":"https://codeload.github.com/at-grandpa/clim/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249016624,"owners_count":21198833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clim","command-line-interface-builder","crystal"],"created_at":"2024-07-31T17:01:03.271Z","updated_at":"2025-04-15T06:05:20.133Z","avatar_url":"https://github.com/at-grandpa.png","language":"Crystal","funding_links":[],"categories":["CLI Builders","Cli Builders"],"sub_categories":[],"readme":"# clim\n\n\"clim\" is slim command line interface builder for Crystal.\n\n_\"clim\" = \"cli\" + \"slim\"_\n\n![spec1](https://github.com/at-grandpa/clim/workflows/spec1/badge.svg)\n![spec2](https://github.com/at-grandpa/clim/workflows/spec2/badge.svg)\n![spec3](https://github.com/at-grandpa/clim/workflows/spec3/badge.svg)\n![spec4](https://github.com/at-grandpa/clim/workflows/spec4/badge.svg)\n![spec5](https://github.com/at-grandpa/clim/workflows/spec5/badge.svg)\n![format-check](https://github.com/at-grandpa/clim/workflows/check-formatting/badge.svg)\n![completion](https://github.com/at-grandpa/clim/workflows/completion/badge.svg)\n\n## Goals\n\n* Slim implementation.\n* Intuitive code.\n\n## Support\n\n- [x] Option types\n  - [x] `Int8`\n  - [x] `Int16`\n  - [x] `Int32`\n  - [x] `Int64`\n  - [x] `UInt8`\n  - [x] `UInt16`\n  - [x] `UInt32`\n  - [x] `UInt64`\n  - [x] `Float32`\n  - [x] `Float64`\n  - [x] `String`\n  - [x] `Bool`\n  - [x] `Array(Int8)`\n  - [x] `Array(Int16)`\n  - [x] `Array(Int32)`\n  - [x] `Array(Int64)`\n  - [x] `Array(UInt8)`\n  - [x] `Array(UInt16)`\n  - [x] `Array(UInt32)`\n  - [x] `Array(UInt64)`\n  - [x] `Array(Float32)`\n  - [x] `Array(Float64)`\n  - [x] `Array(String)`\n- [x] Argument types\n  - [x] `Int8`\n  - [x] `Int16`\n  - [x] `Int32`\n  - [x] `Int64`\n  - [x] `UInt8`\n  - [x] `UInt16`\n  - [x] `UInt32`\n  - [x] `UInt64`\n  - [x] `Float32`\n  - [x] `Float64`\n  - [x] `String`\n  - [x] `Bool`\n- [x] Default values for option \u0026 argument\n- [x] Required flag for option \u0026 argument\n- [x] Nested sub commands\n- [x] `--help` option\n- [x] Customizable help message\n- [x] `version` macro\n- [x] Command name alias\n- [x] Bash completion\n\n\n## Installation\n\nAdd this to your application's `shard.yml`:\n\n```yaml\ndependencies:\n  clim:\n    github: at-grandpa/clim\n    version: 0.17.1\n```\n\n## Samples\n\n### Minimum sample\n\n*src/minimum.cr*\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    run do |opts, args|\n      puts \"#{args.all_args.join(\", \")}!\"\n    end\n  end\nend\n\nMyCli.start(ARGV)\n```\n\n```console\n$ crystal build -o ./minimum src/minimum.cr\n$ ./minimum foo bar baz\nfoo, bar, baz!\n```\n\n### Command information sample\n\n*src/hello.cr*\n\n```crystal\nrequire \"clim\"\n\nmodule Hello\n  class Cli \u003c Clim\n    main do\n      desc \"Hello CLI tool.\"\n      usage \"hello [options] [arguments] ...\"\n      version \"Version 0.1.0\"\n      option \"-g WORDS\", \"--greeting=WORDS\", type: String, desc: \"Words of greetings.\", default: \"Hello\"\n      argument \"first_member\", type: String, desc: \"first member name.\", default: \"member1\"\n      argument \"second_member\", type: String, desc: \"second member name.\", default: \"member2\"\n      run do |opts, args|\n        print \"#{opts.greeting}, \"\n        print \"#{args.first_member} \u0026 #{args.second_member} !\\n\"\n        print \"And #{args.unknown_args.join(\", \")} !\"\n        print \"\\n\"\n      end\n    end\n  end\nend\n\nHello::Cli.start(ARGV)\n```\n\n```console\n$ crystal build src/hello.cr\n$ ./hello --help\n\n  Hello CLI tool.\n\n  Usage:\n\n    hello [options] [arguments] ...\n\n  Options:\n\n    -g WORDS, --greeting=WORDS       Words of greetings. [type:String] [default:\"Hello\"]\n    --help                           Show this help.\n    --version                        Show version.\n\n  Arguments:\n\n    01. first_member       first member name. [type:String] [default:\"member1\"]\n    02. second_member      second member name. [type:String] [default:\"member2\"]\n\n$ ./hello -g 'Good night' Ichiro Miko Takashi Taro\nGood night, Ichiro \u0026 Miko !\nAnd Takashi, Taro !\n```\n\n### Sub commands sample\n\n*src/fake-crystal-command.cr*\n\n```crystal\nrequire \"clim\"\n\nmodule FakeCrystalCommand\n  class Cli \u003c Clim\n    main do\n      desc \"Fake Crystal command.\"\n      usage \"fcrystal [sub_command] [arguments]\"\n      run do |opts, args|\n        puts opts.help_string # =\u003e help string.\n      end\n      sub \"tool\" do\n        desc \"run a tool\"\n        usage \"fcrystal tool [tool] [arguments]\"\n        run do |opts, args|\n          puts \"Fake Crystal tool!!\"\n        end\n        sub \"format\" do\n          desc \"format project, directories and/or files\"\n          usage \"fcrystal tool format [options] [file or directory]\"\n          run do |opts, args|\n            puts \"Fake Crystal tool format!!\"\n          end\n        end\n      end\n      sub \"spec\" do\n        desc \"build and run specs\"\n        usage \"fcrystal spec [options] [files]\"\n        run do |opts, args|\n          puts \"Fake Crystal spec!!\"\n        end\n      end\n    end\n  end\nend\n\nFakeCrystalCommand::Cli.start(ARGV)\n```\n\nBuild and run.\n\n```console\n$ crystal build -o ./fcrystal src/fake-crystal-command.cr\n$ ./fcrystal\n\n  Fake Crystal command.\n\n  Usage:\n\n    fcrystal [sub_command] [arguments]\n\n  Options:\n\n    --help                           Show this help.\n\n  Sub Commands:\n\n    tool   run a tool\n    spec   build and run specs\n\n```\n\nShow sub command help.\n\n```console\n$ ./fcrystal tool --help\n\n  run a tool\n\n  Usage:\n\n    fcrystal tool [tool] [arguments]\n\n  Options:\n\n    --help                           Show this help.\n\n  Sub Commands:\n\n    format   format project, directories and/or files\n\n```\n\nRun sub sub command.\n\n```console\n$ ./fcrystal tool format\nFake Crystal tool format!!\n```\n\n## How to use\n\n### require \u0026 inherit\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n\n  # ...\n\nend\n```\n\n### Command Informations\n\n#### desc\n\nDescription of the command. It is displayed in Help.\n\n```crystal\nclass MyCli \u003c Clim\n  main do\n    desc \"My Command Line Interface.\"\n    run do |opts, args|\n      # ...\n    end\n  end\nend\n```\n\n#### usage\n\nUsage of the command. It is displayed in Help.\n\n```crystal\nclass MyCli \u003c Clim\n  main do\n    usage  \"mycli [sub-command] [options] ...\"\n    run do |opts, args|\n      # ...\n    end\n  end\nend\n```\n\n#### alias_name\n\nAn alias for the command. It can be specified only for subcommand.\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    run do |opts, args|\n      # ...\n    end\n    sub \"sub\" do\n      alias_name  \"alias1\", \"alias2\"\n      run do |opts, args|\n        puts \"sub_command run!!\"\n      end\n    end\n  end\nend\n\nMyCli.start(ARGV)\n```\n\n```console\n$ ./mycli sub\nsub_command run!!\n$ ./mycli alias1\nsub_command run!!\n$ ./mycli alias2\nsub_command run!!\n```\n\n#### version\n\nYou can specify the string to be displayed with `--version`.\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    version \"mycli version: 1.0.1\"\n    run do |opts, args|\n      # ...\n    end\n  end\nend\n\nMyCli.start(ARGV)\n```\n\n```console\n$ ./mycli --version\nmycli version: 1.0.1\n```\n\nIf you want to display it even with `-v`, add ` short: \"-v\" `.\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    version \"mycli version: 1.0.1\", short: \"-v\"\n    run do |opts, args|\n      # ...\n    end\n  end\nend\n\nMyCli.start(ARGV)\n```\n\n```console\n$ ./mycli --version\nmycli version: 1.0.1\n$ ./mycli -v\nmycli version: 1.0.1\n```\n\n#### Short option for help\n\nThe short help option is not set by default. If you want help to appear by specifying `-h` , specify `help short: \"-h\"` .\n\n(However, it should not conflict with other options.)\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    desc \"help directive test.\"\n    usage \"mycli [options] [arguments]\"\n    help short: \"-h\"\n    run do |opts, args|\n      # ...\n    end\n  end\nend\n\nMyCli.start(ARGV)\n```\n\n```console\n$ ./mycli -h\n\n  help directive test.\n\n  Usage:\n\n    mycli [options] [arguments]\n\n  Options:\n\n    -h, --help                       Show this help.\n\n$ ./mycli --help\n\n  help directive test.\n\n  Usage:\n\n    mycli [options] [arguments]\n\n  Options:\n\n    -h, --help                       Show this help.\n\n```\n\nIn addition to `-h`, you can specify any single character. For example, `help short: \"-a\"` .\n\n#### option\n\nYou can specify multiple options for the command.\n\n | Argument        | Description        | Example                       | Required | Default                 |\n | --------------- | ------------------ | ----------------------------- | -------- | ----------------------- |\n | First argument  | short or long name | `-t TIMES`, `--times TIMES`   | true     | -                       |\n | Second argument | long name          | `--times TIMES`               | false    | -                       |\n | `type`          | option type        | `type: Array(Float32)`        | false    | `String`                |\n | `desc`          | option description | `desc: \"option description.\"` | false    | `\"Option description.\"` |\n | `default`       | default value      | `default: [1.1_f32, 2.2_f32]` | false    | `nil`                   |\n | `required`      | required flag      | `required: true`              | false    | `false`                 |\n\n```crystal\nclass MyCli \u003c Clim\n  main do\n    option \"--greeting=WORDS\", desc: \"Words of greetings.\", default: \"Hello\"\n    option \"-n NAME\", \"--name=NAME\", type: Array(String), desc: \"Target name.\", default: [\"Taro\"]\n    run do |opts, args|\n      puts typeof(opts.greeting) # =\u003e String\n      puts typeof(opts.name)     # =\u003e Array(String)\n    end\n  end\nend\n```\n\nThe type of the option is determined by the `default` and `required` patterns.\n\n*Number*\n\nFor example `Int8`.\n\n | `default` | `required` | Type                                    |\n | --------- | ---------- | --------------------------------------- |\n | exist     | `true`     | `Int8` (default: Your specified value.) |\n | exist     | `false`    | `Int8` (default: Your specified value.) |\n | not exist | `true`     | `Int8`                                  |\n | not exist | `false`    | `Int8 \\| Nil`                           |\n\n*String*\n\n | `default` | `required` | Type                                      |\n | --------- | ---------- | ----------------------------------------- |\n | exist     | `true`     | `String` (default: Your specified value.) |\n | exist     | `false`    | `String` (default: Your specified value.) |\n | not exist | `true`     | `String`                                  |\n | not exist | `false`    | `String \\| Nil`                           |\n\n*Bool*\n\n | `default` | `required` | Type                                    |\n | --------- | ---------- | --------------------------------------- |\n | exist     | `true`     | `Bool` (default: Your specified value.) |\n | exist     | `false`    | `Bool` (default: Your specified value.) |\n | not exist | `true`     | `Bool`                                  |\n | not exist | `false`    | `Bool` (default: `false`)               |\n\n*Array*\n\n | `default` | `required` | Type                                        |\n | --------- | ---------- | ------------------------------------------- |\n | exist     | `true`     | `Array(T)` (default: Your specified value.) |\n | exist     | `false`    | `Array(T)` (default: Your specified value.) |\n | not exist | `true`     | `Array(T)`                                  |\n | not exist | `false`    | `Array(T)` (default: `[] of T`)             |\n\nFor Bool, you do not need to specify arguments for short or long.\n\n```crystal\nclass MyCli \u003c Clim\n  main do\n    option \"-v\", \"--verbose\", type: Bool, desc: \"Verbose.\"\n    run do |opts, args|\n      puts typeof(opts.verbose) # =\u003e Bool\n    end\n  end\nend\n```\n\nOption 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.\n\n```crystal\nclass MyCli \u003c Clim\n  main do\n    option \"-n\", type: String, desc: \"name.\"  # =\u003e short name only.\n    option \"--my-age\", type: Int32, desc: \"age.\" # =\u003e long name only.\n    run do |opts, args|\n      puts typeof(opts.n)      # =\u003e (String | Nil)\n      puts typeof(opts.my_age) # =\u003e (Int32 | Nil)\n    end\n  end\nend\n```\n\n#### argument\n\nYou can specify multiple arguments for the command.\n\n | Argument       | Description          | Example                         | Required | Default                   |\n | -------------- | -------------------- | ------------------------------- | -------- | ------------------------- |\n | First argument | name                 | `my_argument`                   | true     | -                         |\n | `type`         | argument type        | `type: String`                  | false    | `String`                  |\n | `desc`         | argument description | `desc: \"argument description.\"` | false    | `\"Argument description.\"` |\n | `default`      | default value        | `default: \"default value\"`      | false    | `nil`                     |\n | `required`     | required flag        | `required: true`                | false    | `false`                   |\n\nThe order of the arguments is related to the order in which they are defined. Also, when calling a method, hyphens in the method name of the argument are converted to underscores. There are also `all_args`, `unknown_args` and `argv` methods.\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    desc \"argument sample\"\n    usage \"command [options] [arguments]\"\n\n    option \"--dummy=WORDS\",\n      desc: \"dummy option\"\n\n    argument \"first-arg\",\n      desc: \"first argument!\",\n      type: String,\n      default: \"default value\"\n\n    argument \"second-arg\",\n      desc: \"second argument!\",\n      type: Int32,\n      default: 999\n\n    run do |opts, args|\n      puts \"typeof(args.first_arg)    =\u003e #{typeof(args.first_arg)}\"\n      puts \"       args.first_arg     =\u003e #{args.first_arg}\"\n      puts \"typeof(args.second_arg)   =\u003e #{typeof(args.second_arg)}\"\n      puts \"       args.second_arg    =\u003e #{args.second_arg}\"\n      puts \"typeof(args.all_args)     =\u003e #{typeof(args.all_args)}\"\n      puts \"       args.all_args      =\u003e #{args.all_args}\"\n      puts \"typeof(args.unknown_args) =\u003e #{typeof(args.unknown_args)}\"\n      puts \"       args.unknown_args  =\u003e #{args.unknown_args}\"\n      puts \"typeof(args.argv)         =\u003e #{typeof(args.argv)}\"\n      puts \"       args.argv          =\u003e #{args.argv}\"\n    end\n  end\nend\n\n```\n\n```console\n$ crystal run src/argument.cr -- --help\n\n  argument sample\n\n  Usage:\n\n    command [options] [arguments]\n\n  Options:\n\n    --dummy=WORDS                    dummy option [type:String]\n    --help                           Show this help.\n\n  Arguments:\n\n    01. first-arg       first argument! [type:String] [default:\"default value\"]\n    02. second-arg      second argument! [type:Int32] [default:999]\n\n$ crystal run src/argument.cr -- 000 111 --dummy dummy_words 222 333\ntypeof(args.first_arg)    =\u003e String\n       args.first_arg     =\u003e 000\ntypeof(args.second_arg)   =\u003e Int32\n       args.second_arg    =\u003e 111\ntypeof(args.all_args)     =\u003e Array(String)\n       args.all_args      =\u003e [\"000\", \"111\", \"222\", \"333\"]\ntypeof(args.unknown_args) =\u003e Array(String)\n       args.unknown_args  =\u003e [\"222\", \"333\"]\ntypeof(args.argv)         =\u003e Array(String)\n       args.argv          =\u003e [\"000\", \"111\", \"--dummy\", \"dummy_words\", \"222\", \"333\"]\n\n```\n\nThe type of the arguments is determined by the `default` and `required` patterns.\n\n*Number*\n\nFor example `Int8`.\n\n | `default` | `required` | Type                                    |\n | --------- | ---------- | --------------------------------------- |\n | exist     | `true`     | `Int8` (default: Your specified value.) |\n | exist     | `false`    | `Int8` (default: Your specified value.) |\n | not exist | `true`     | `Int8`                                  |\n | not exist | `false`    | `Int8 \\| Nil`                           |\n\n*String*\n\n | `default` | `required` | Type                                      |\n | --------- | ---------- | ----------------------------------------- |\n | exist     | `true`     | `String` (default: Your specified value.) |\n | exist     | `false`    | `String` (default: Your specified value.) |\n | not exist | `true`     | `String`                                  |\n | not exist | `false`    | `String \\| Nil`                           |\n\n*Bool*\n\n | `default` | `required` | Type                                    |\n | --------- | ---------- | --------------------------------------- |\n | exist     | `true`     | `Bool` (default: Your specified value.) |\n | exist     | `false`    | `Bool` (default: Your specified value.) |\n | not exist | `true`     | `Bool`                                  |\n | not exist | `false`    | `Bool \\| Nil`                           |\n\n### help_template\n\nYou can customize the help message by `help_template` block. It must be placed in main block. Also it needs to return `String`. Block arguments are `desc : String`, `usage : String`, `options : HelpOptionsType`, `argments : HelpArgumentsType` and `sub_commands : HelpSubCommandsType`.\n\n*help_template_test.cr*\n\n```crystal\nrequire \"clim\"\n\nclass MyCli \u003c Clim\n  main do\n    help_template do |desc, usage, options, arguments, sub_commands|\n      options_help_lines = options.map do |option|\n        option[:names].join(\", \") + \"\\n\" + \"    #{option[:desc]}\"\n      end\n      arguments_help_lines = arguments.map do |argument|\n        (\"%02d: \" % [argument[:sequence_number]]) +\n          argument[:display_name] +\n          \"\\n\" +\n          \"      #{argument[:desc]}\"\n      end\n\n      base = \u003c\u003c-BASE_HELP\n      #{usage}\n\n      #{desc}\n\n      options:\n      #{options_help_lines.join(\"\\n\")}\n\n      arguments:\n      #{arguments_help_lines.join(\"\\n\")}\n\n      BASE_HELP\n\n      sub = \u003c\u003c-SUB_COMMAND_HELP\n\n      sub commands:\n      #{sub_commands.map(\u0026.[](:help_line)).join(\"\\n\")}\n      SUB_COMMAND_HELP\n\n      sub_commands.empty? ? base : base + sub\n    end\n    desc \"Your original command line interface tool.\"\n    usage \u003c\u003c-USAGE\n    usage: my_cli [--version] [--help] [-P PORT|--port=PORT]\n                  [-h HOST|--host=HOST] [-p PASSWORD|--password=PASSWORD] [arguments]\n    USAGE\n    version \"version 1.0.0\"\n    option \"-P PORT\", \"--port=PORT\", type: Int32, desc: \"Port number.\", default: 3306\n    option \"-h HOST\", \"--host=HOST\", type: String, desc: \"Host name.\", default: \"localhost\"\n    option \"-p PASSWORD\", \"--password=PASSWORD\", type: String, desc: \"Password.\"\n    argument \"image_name\", type: String, desc: \"The name of your favorite docker image.\"\n    argument \"container_id\", type: String, desc: \"The ID of the running container.\"\n    run do |opts, args|\n    end\n    sub \"sub_command\" do\n      desc \"my_cli's sub_comand.\"\n      run do |opts, args|\n      end\n    end\n  end\nend\n\nMyCli.start(ARGV)\n```\n\n```console\n$ crystal run src/help_template_test.cr -- --help\nusage: my_cli [--version] [--help] [-P PORT|--port=PORT]\n              [-h HOST|--host=HOST] [-p PASSWORD|--password=PASSWORD] [arguments]\n\nYour original command line interface tool.\n\noptions:\n-P PORT, --port=PORT\n    Port number.\n-h HOST, --host=HOST\n    Host name.\n-p PASSWORD, --password=PASSWORD\n    Password.\n--help\n    Show this help.\n--version\n    Show version.\n\narguments:\n01: image_name\n      The name of your favorite docker image.\n02: container_id\n      The ID of the running container.\n\nsub commands:\n    sub_command   my_cli's sub_comand.\n\n```\n\noptions:\n\n```crystal\n# `options` type\nalias HelpOptionsType = Array(NamedTuple(\n    names:     Array(String),\n    type:      Int8.class | Int32.class | ... | String.class | Bool.class, # =\u003e Support Types\n    desc:      String,\n    default:   Int8 | Int32 | ... | String | Bool, # =\u003e Support Types,\n    required:  Bool,\n    help_line: String\n))\n\n# `options` example\n[\n  {\n    names:     [\"-g WORDS\", \"--greeting=WORDS\"],\n    type:      String,\n    desc:      \"Words of greetings.\",\n    default:   \"Hello\",\n    required:  false,\n    help_line: \"    -g WORDS, --greeting=WORDS       Words of greetings. [type:String] [default:\\\"Hello\\\"]\",\n  },\n  {\n    names:     [\"-n NAME\"],\n    type:      Array(String),\n    desc:      \"Target name.\",\n    default:   [\"Taro\"],\n    required:  true,\n    help_line: \"    -n NAME                          Target name. [type:Array(String)] [default:[\\\"Taro\\\"]] [required]\",\n  },\n  {\n    names:     [\"--help\"],\n    type:      Bool,\n    desc:      \"Show this help.\",\n    default:   false,\n    required:  false,\n    help_line: \"    --help                           Show this help.\",\n  },\n]\n```\narguments:\n\n```crystal\n# `arguments` type\nalias HelpArgumentsType = Array(NamedTuple(\n    method_name:     String,\n    display_name:    String,\n    type:            Int8.class | Int32.class | ... | String.class | Bool.class, # =\u003e Support Types\n    desc:            String,\n    default:         Int8 | Int32 | ... | String | Bool, # =\u003e Support Types,\n    required:        Bool,\n    sequence_number: Int32,\n    help_line:       String\n))\n\n# `arguments` example\n[\n  {\n    method_name:     \"argument1\",\n    display_name:    \"argument1\",\n    type:            String,\n    desc:            \"first argument.\",\n    default:         \"default value\",\n    required:        true,\n    sequence_number: 1,\n    help_line:       \"    01. argument1            first argument. [type:String] [default:\\\"default value\\\"] [required]\",\n  },\n  {\n    method_name:     \"argument2foo\",\n    display_name:    \"argument2foo\",\n    type:            Int32,\n    desc:            \"second argument.\",\n    default:         1,\n    required:        false,\n    sequence_number: 2,\n    help_line:       \"    02. argument2foo         second argument. [type:Int32] [default:1]\",\n  },\n]\n```\n\nsub_commands:\n\n```crystal\n# `sub_commands` type\nalias HelpSubCommandsType = Array(NamedTuple(\n    names:     Array(String),\n    desc:      String,\n    help_line: String\n))\n\n# `sub_commands` example\n[\n  {\n    names:     [\"abc\", \"def\", \"ghi\"],\n    desc:      \"abc command.\",\n    help_line: \"    abc, def, ghi            abc command.\",\n  },\n  {\n    names:     [\"abcdef\", \"ghijkl\", \"mnopqr\"],\n    desc:      \"abcdef command.\",\n    help_line: \"    abcdef, ghijkl, mnopqr   abcdef command.\",\n  },\n]\n```\n\n### help string\n\n```crystal\nclass MyCli \u003c Clim\n  main do\n    run do |opts, args|\n      opts.help_string # =\u003e help string\n    end\n  end\nend\n```\n\n### `io` in run block\n\nYou can receive `io` in a run block by passing it as the second argument to the start method.\n\n```crystal\nrequire \"clim\"\n\nclass IoCommand \u003c Clim\n  main do\n    run do |opts, args, io|\n      io.puts \"in main\"\n    end\n  end\nend\n\nio = IO::Memory.new\nIoCommand.start([] of String, io: io)\nputs io.to_s # =\u003e \"in main\\n\"\n```\n\n### Bash completion\n\nYou can use bash completion.\n\n*src/sample.cr*\n\n```crystal\nrequire \"clim\"\n\nclass Cli \u003c Clim\n  main do\n    version \"Version 1.0\"\n    option \"-p PORT\", \"--port=PORT\", type: Int32, desc: \"Port number.\"\n    option \"-h HOST\", \"--host=HOST\", type: String, desc: \"Host name.\"\n    run do |opts, args|\n      # ...\n    end\n\n    sub \"tool\" do\n      option \"-v\", \"--verbose\", type: Bool\n      run do |opts, args|\n        # ...\n      end\n    end\n\n    sub \"run\" do\n      help short: \"-h\"\n      run do |opts, args|\n        # ...\n      end\n    end\n  end\nend\n\nCli.start(ARGV)\n```\n\n- Step1: Build your program.\n- Step2: Add ```eval \"`{your_program} --bash-completion`\"``` to `~/.bashrc`.\n- Step3: Reload `~/.bashrc`.\n- Step4: You can use bash completion for options and subcommands.\n\n```console\n$ crystal build src/sample.cr -o /usr/local/bin/sample\n$ echo 'eval \"`sample --bash-completion`\"' \u003e\u003e ~/.bashrc\n$ . ~/.bashrc\n$ sample [TAB][TAB]\n--help     --host     --port     --version  -h         -p         run        tool\n$ sample tool -[TAB][TAB]\n--help     --verbose  -v\n$ sample tool --[TAB][TAB]\n--help     --verbose\n$ sample tool --help\n\n  Command Line Interface Tool.\n\n  Usage:\n\n    tool [options] [arguments]\n\n  Options:\n\n    -v, --verbose                    Option description. [type:Bool]\n    --help                           Show this help.\n\n$\n```\n\n\n## Development\n\n```\n$ make spec\n```\n\n## Contributing\n\n1. Fork it ( https://github.com/at-grandpa/clim/fork )\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'Add some feature')\n4. Push to the branch (git push origin my-new-feature)\n5. Create a new Pull Request\n\n## Contributors\n\n- [at-grandpa](https://github.com/at-grandpa) - creator, maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fat-grandpa%2Fclim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fat-grandpa%2Fclim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fat-grandpa%2Fclim/lists"}