Skip to content

module Athena::Console::Input::Interface #

Athena::Console uses a dedicated interface for representing an input source. This allows it to have multiple more specialized implementations as opposed to being tightly coupled to STDIN or a raw IO. This interface represents the methods that must be implemented, however implementations can add additional functionality.

All input sources follow the docopt standard, used by many CLI utility tools. Documentation on this type covers functionality/logic common to all inputs. See each type for more specific information.

Option and argument values can be accessed via ACON::Input::Interface#option and ACON::Input::Interface#argument respectively. There are two overloads, the first accepting just the name of the option/argument as a String, returning the raw value as a String?, with arrays being represented as a comma separated list. The other two overloads accept a T.class representing the desired type the value should be parsed as. For example, given a command with two required and one array arguments:

protected def configure : Nil
  self
    .argument("bool", :required)
    .argument("int", :required)
    .argument("floats", :is_array)
end

Assuming the invocation is ./console test false 10 3.14 172.0 123.7777, the values could then be accessed like:

protected def execute(input : ACON::Input::Interface, output : ACON::Output::Interface) : ACON::Command::Status
  input.argument "bool"       # => "false" : String
  input.argument "bool", Bool # => false : Bool
  input.argument "int", Int8  # => 10 : Int8

  input.argument "floats"                 # => "3.14,172.0,123.7777" : String
  input.argument "floats", Array(Float64) # => [3.14, 172.0, 123.7777] : Array(Float64)

  ACON::Command::Status::SUCCESS
end

The latter syntax is preferred since it correctly types the value. If a provided value cannot be converted to the expected type, an ACON::Exceptions::Logic exception will be raised. E.g. '123' is not a valid 'Bool'..

Tip

Argument/option modes can be combined. E.g.ACON::Input::Argument::Mode.flags(IS_ARRAY, REQUIRED) for a required array argument. See also: https://github.com/crystal-lang/crystal/issues/10680.

There are a lot of possible combinations in regards to what options are defined versus those are provided. To better illustrate how these cases are handled, let's look at an example of a command with three ACON::Input::Options:

protected def configure : Nil
  self
    .option("foo", "f")
    .option("bar", "b", :required)
    .option("baz", "z", :optional)
end

The value of foo will either be true if provided, otherwise false; this is the default behavior of ACON::Input::Options. The bar (b) option is required to have a value. A value can be separated from the option's long name by either a space or = or by its short name by an optional space. Finally, the baz (z) option's value is optional.

This table shows how the value of each option based on the provided input:

Input foo bar baz
--bar=Hello false "Hello" nil
--bar Hello false "Hello" nil
-b=Hello false "=Hello" nil
-b Hello false "Hello" nil
-bHello false "Hello" nil
-fzWorld -b Hello true "Hello" "World"
-zfWorld -b Hello false "Hello" "fWorld"
-zbWorld false nil "bWorld"

Things get a bit trickier when an optional ACON::Input::Argument:

protected def configure : Nil
  self
    .option("foo", "f")
    .option("bar", "b", :required)
    .option("baz", "z", :optional)
    .argument("arg", :optional)
end

In some cases you may need to use the special -- option in order to denote later values should be parsed as arguments, not as a value to an option:

Input bar baz arg
--bar Hello "Hello" nil nil
--bar Hello World "Hello" nil "World"
--bar "Hello World" "Hello World" nil nil
--bar Hello --baz World "Hello" "World" nil
--bar Hello --baz -- World "Hello" nil "World"
-b Hello -z World "Hello" "World" nil

Direct including types

Athena::Console::Input::Streamable

Methods#

abstract #argument(name : String, type : T.class) forall T #

Returns the value of the argument with the provided name converted to the desired type. This method is preferred over #argument since it provides better typing.

Raises an ACON::Exceptions::Logic if the actual argument value could not be converted to a type.

View source

abstract #argument(name : String) : String? #

Returns the raw string value of the argument with the provided name, or nil if is optional and was not provided.

View source

abstract #arguments : ::Hash #

Returns a ::Hash representing the keys and values of the parsed arguments of self.

View source

abstract #bind(definition : ACON::Input::Definition) : Nil #

Binds the provided definition to self. Essentially provides what should be parsed from self.

View source

abstract #first_argument : String? #

Returns the first argument from the raw un-parsed input. Mainly used to get the command that should be executed.

View source

abstract #has_argument?(name : String) : Bool #

Returns true if self has an argument with the provided name, otherwise false.

View source

abstract #has_option?(name : String) : Bool #

Returns true if self has an option with the provided name, otherwise false.

View source

abstract #has_parameter?(*values : String, only_params : Bool = false) : Bool #

Returns true if the raw un-parsed input contains one of the provided values.

This method is to be used to introspect the input parameters before they have been validated. It must be used carefully. It does not necessarily return the correct result for short options when multiple flags are combined in the same option.

If only_params is true, only real parameters are checked. I.e. skipping those that come after the -- option.

View source

abstract #interactive=(interactive : Bool) #

Sets if self is #interactive?.

View source

abstract #interactive? : Bool #

Returns true if self represents an interactive input, such as a TTY.

View source

abstract #option(name : String, type : T.class) forall T #

Returns the value of the option with the provided name converted to the desired type. This method is preferred over #option since it provides better typing.

Raises an ACON::Exceptions::Logic if the actual option value could not be converted to a type.

View source

abstract #option(name : String) : String? #

Returns the raw string value of the option with the provided name, or nil if is optional and was not provided.

View source

abstract #options : ::Hash #

Returns a ::Hash representing the keys and values of the parsed options of self.

View source

abstract #parameter(value : String, default : _ = false, only_params : Bool = false) #

Returns the value of a raw un-parsed parameter for the provided value..

This method is to be used to introspect the input parameters before they have been validated. It must be used carefully. It does not necessarily return the correct result for short options when multiple flags are combined in the same option.

If only_params is true, only real parameters are checked. I.e. skipping those that come after the -- option.

View source

abstract #set_argument(name : String, value : _) : Nil #

Sets the value of the argument with the provided name.

View source

abstract #set_option(name : String, value : _) : Nil #

Sets the value of the option with the provided name.

View source

abstract #validate : Nil #

Validates the input, asserting all of the required parameters are provided. Raises ACON::Exceptions::ValidationFailed if not valid.

View source