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::Exception::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[:required, :is_array]
for a required array argument.
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::Option
s:
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::Option
s.
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 |
Argument/Option Value Completion#
If the completion script is installed, command and option names will be auto completed by the shell. However, value completion may also be implemented in custom commands by providing the suggested values for a particular option/argument.
@[ACONA::AsCommand("greet")]
class GreetCommand < ACON::Command
protected def configure : Nil
# The suggested values do not need to be a static array,
# they could be sourced via a class/instance method, a constant, etc.
self
.argument("name", suggested_values: ["Jim", "Bob", "Sally"])
end
# ...
end
Additionally, a block version of ACON::Command#argument(name,mode,description,default,&)
and ACON::Command#option(name,shortcut,value_mode,description,default,&)
may be used if more complex logic is required.
@[ACONA::AsCommand("greet")]
class GreetCommand < ACON::Command
protected def configure : Nil
self
.argument("name") do |input|
# The value the user already typed, e.g. the value the user already typed,
# e.g. when typing "greet Ge" before pressing Tab, this will contain "Ge".
current_value = input.completion_value
# Get the list of username names from somewhere (e.g. the database)
# you may use current_value to filter down the names
available_usernames = ...
# then suggested the usernames as values
return available_usernames
end
end
# ...
end
Tip
The shell completion script is able to handle huge amounts of suggestions and will automatically filter
the values based on existing input from the user.
You do not have to implement any filter logic in the command.
input.completion_value
can still be used to filter if it helps with performance, such as reducing amount of rows the DB returns.
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::Exception::Logic
if the actual argument value could not be converted to a type.
abstract #argument(name : String) : String | Nil
#
Returns the raw string value of the argument with the provided name, or nil
if is optional and was not provided.
abstract #arguments : ::Hash
#
Returns a ::Hash
representing the keys and values of the parsed arguments of self
.
abstract #bind(definition : ACON::Input::Definition) : Nil
#
Binds the provided definition to self
.
Essentially provides what should be parsed from self
.
abstract #first_argument : String | ::Nil
#
Returns the first argument from the raw un-parsed input. Mainly used to get the command that should be executed.
abstract #has_argument?(name : String) : Bool
#
Returns true
if self
has an argument with the provided name, otherwise false
.
abstract #has_option?(name : String) : Bool
#
Returns true
if self
has an option with the provided name, otherwise false
.
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.
abstract #interactive? : Bool
#
Returns true
if self
represents an interactive input, such as a TTY.
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::Exception::Logic
if the actual option value could not be converted to a type.
abstract #option(name : String) : String | Nil
#
Returns the raw string value of the option with the provided name, or nil
if is optional and was not provided.
abstract #options : ::Hash
#
Returns a ::Hash
representing the keys and values of the parsed options of self
.
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.
abstract #set_argument(name : String, value : _) : Nil
#
Sets the value of the argument with the provided name.
abstract #set_option(name : String, value : _) : Nil
#
Sets the value of the option with the provided name.
abstract #to_s(io : IO) : Nil
#
Returns a string representation of the args passed to the command.
abstract #validate : Nil
#
Validates the input, asserting all of the required parameters are provided.
Raises ACON::Exception::Runtime
when not enough arguments are given.