diff options
author | gearnode <bryan@frimin.fr> | 2020-09-02 16:05:29 +0200 |
---|---|---|
committer | gearnode <bryan@frimin.fr> | 2020-09-02 16:05:29 +0200 |
commit | 33e1e9b07948540b45be92bf4c567d8735571d32 (patch) | |
tree | 708b60e5ca6e96ba5b537facb11b393255e8d32b | |
parent | 9416aca6eb394c01c31d51ece938ec926731a49b (diff) |
update documentation
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | README.md | 39 | ||||
-rw-r--r-- | doc/handbook.md | 86 | ||||
-rw-r--r-- | lib/cmdline.rb | 145 |
4 files changed, 273 insertions, 1 deletions
@@ -1 +1,5 @@ *.gem +/pkg/ +/.yardoc/ +/doc/* +!/doc/handbook.md @@ -1 +1,38 @@ -# rb-cmdline +# Introduction +`RbCmdline` is a simple Ruby library to built command line interface. + +# Motivation +Existing Ruby library to build command line interface have complex API and +abuse a of DSL. This library expose a simple API and do not use any DSL. + +# Documentation +The [handbook](doc/handbook.md) contains information about various aspects of +the library. + +You can also use the [yard](https://yardoc.org) documentation tool to read +code documentation, for example: + + yard doc + +# Contact +If you find a bug or have any question, feel free to open a Github issue or to +contact me [by email](mailto:bryan@frimin.fr). + +Please note that I do not currently review or accept any contribution. + +# License +Released under the ISC license. + +Copyright (c) 2020 Bryan Frimin <bryan@frimin.fr>. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/doc/handbook.md b/doc/handbook.md new file mode 100644 index 0000000..e79c68c --- /dev/null +++ b/doc/handbook.md @@ -0,0 +1,86 @@ +# Introduction +This document explain how to use the `rb-cmdline` library. + +# Usage +## Minimal +```ruby +require("rb-cmdline") + +cmd = Cmdline.new +cmd.parse(Cmdline.argv) +``` +## Options +```ruby +require("rb-cmdline") + +cmd = Cmdline.new +cmd.add_option("a", "option-a", "value", "a simple option") +cmd.set_option_default("a", "42") +cmd.add_option("b", "", "value", "an short option") +cmd.add_option("", "option-c", "value", "a long option") +cmd.add_flag("d", "flag-d", "a simple flag") +cmd.parse(Cmdline.argv) + +printf("a: %s\n", cmd.option_value("a")) + +if cmd.is_option_set("b") + printf("b: %s\n", cmd.option_value("b")) +end + +if cmd.is_option_set("option-c") + printf("option-c: %s\n", cmd.option_value("option-c")) +end + +printf("d: %s\n", cmd.is_option_set("d")) +``` + +## Arguments +```ruby +#!/usr/bin/env ruby + +require("rb-cmdline") + +cmd = Cmdline.new +cmd.add_argument("foo", "the first argument") +cmd.add_argument("bar", "the second argument") +cmd.add_trailing_arguments("name", "a trailing argument") + +cmd.parse(Cmdline.argv) + +printf("foo: %s\n", cmd.argument_value("foo")) +printf("bar: %s\n", cmd.argument_value("bar")) +printf("names: %s\n", cmd.trailing_arguments_values("name")) +``` + +## Commands +```ruby +#!/usr/bin/env ruby + +require("rb-cmdline") + +cmd = Cmdline.new + +cmd.add_command("foo", "subcommand 1") +cmd.add_command("bar", "subcommand 2") + +cmd.parse(Cmdline.argv) + +commands = { + "foo" => -> (args) { + printf("running command \"foo\" with arguments %s\n", args[1..]) + }, + "bar" => -> (args) { + cmd = CLI.new + cmd.add_option("n", "", "value", "an example value") + cmd.parse(args) + + printf("running command \"bar\" with arguments %s\n", args[1..]) + + if cmd.is_option_set("n") + printf("n: %s\n", cmd.option_value("n")) + end + } +} + +commands[cmd.command_name].call(cmd.command_name_and_arguments) +``` diff --git a/lib/cmdline.rb b/lib/cmdline.rb index 2d909a7..9bbb047 100644 --- a/lib/cmdline.rb +++ b/lib/cmdline.rb @@ -98,6 +98,16 @@ module Cmdline self.program_name ||= "" end + # Add flag to the command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] short the short name of the flag + # @param [String] long the long name of the flag + # @param [String] description the description of the flag + # + # @return [void] def add_flag(short, long, description) option = Option.new( short_name: short.to_s, @@ -109,6 +119,17 @@ module Cmdline addopt(option) end + # Add option to the command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] short the short name of the option + # @param [String] long the long name of the option + # @param [String] value the demo value of the option + # @param [String] description the description of the option + # + # @return [void] def add_option(short, long, value, description) option = Option.new( short_name: short.to_s, @@ -120,6 +141,15 @@ module Cmdline addopt(option) end + # A default value to an option. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the option + # @param [Object] value the default value of the option + # + # @return [void] def set_option_default(name, value) option = self.options[name] raise(ArgumentError, "unknown option") if option.nil? @@ -128,6 +158,15 @@ module Cmdline option.default = value end + # Add argument to the command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the argument name + # @param [String] description the description of the argument + # + # @return [void] def add_argument(name, description) argument = Argument.new( name: name.to_s, @@ -137,6 +176,15 @@ module Cmdline addarg(argument) end + # Add trailing argument to the command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the trailing arguments + # @param [String] description the description of the trailing arguments + # + # @return [void] def add_trailing_arguments(name, description) argument = Argument.new( name: name.to_s, @@ -147,6 +195,17 @@ module Cmdline addarg(argument) end + # Add command to the command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the command + # @param [String] description the description of the command + # + # @raise [ArgumentError] when the command line has already argument + # + # @return [void] def add_command(name, description) if self.arguments.size.zero? add_argument("command", "the command to execute") @@ -162,12 +221,28 @@ module Cmdline self.commands[cmd.name] = cmd end + # Exit with error. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param (see Kernel#sprintf) + # + # @return [nil] def die(format, *args) msg = sprintf(format, *args) STDERR.puts("error: #{msg}") exit(1) end + # Parse the argument values. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [Array<String>] args + # + # @return [void] def parse(args) die("empty argument array") if args.size == 0 @@ -249,6 +324,12 @@ module Cmdline end end + # Print the usage of the command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @return [void] def print_usage usage = sprintf("Usage: %s OPTIONS", self.program_name) if self.arguments.size > 0 @@ -343,12 +424,32 @@ module Cmdline printf(usage) end + # Check if an option is set. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the option + # + # @raise [ArgumentError] when the option does not exist + # + # @return [Boolean] def is_option_set(name) opt = self.options[name] raise(ArgumentError, "unknown option") if opt.nil? opt.set end + # Get the value of an option. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the option + # + # @raise [ArgumentError] when the option does not exist + # + # @return [String] def option_value(name) opt = self.options[name] raise(ArgumentError, "unknown option") if opt.nil? @@ -357,6 +458,16 @@ module Cmdline opt.default end + # Get the value of an argument. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the argument + # + # @raise [ArgumentError] when the argument does not exist. + # + # @return [String] def argument_value(name) self.arguments.each do |arg| if arg.name == name @@ -366,6 +477,16 @@ module Cmdline raise(ArgumentError, "unknown argument") end + # Get the values of the trailing arguments. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @param [String] name the name of the trailing arguments. + # + # @raise [ArgumentError] when the trailing arguments are empty. + # + # @return [Array<String>] def trailing_arguments_values(name) raise(ArgumentError, "empty argument array") if self.arguments.empty? last = self.arguments.last @@ -373,16 +494,34 @@ module Cmdline last.trailing_values end + # Get the name of command to execute. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @return [String] def command_name raise(RuntimeError, "no command defined") if self.commands.empty? self.command end + # Get command arguments. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @return [Array<String>] def command_arguments_values raise(RuntimeError, "no command defined") if self.commands.empty? self.command_arguments end + # Get the command name and their arguments. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @return [Array<String>] def command_name_and_arguments raise(RuntimeError, "no command defined") if self.commands.empty? [self.command, *self.command_arguments] @@ -421,6 +560,12 @@ module Cmdline end end + # Create new command line interface. + # + # @author Gearnode <bryan@frimin.fr> + # @since 1.0.0 + # + # @return [CmdLine] def self.new cmd = CmdLine.new cmd.add_flag("h", "help", "print help and exit") |