Option normalizers

The goal of option normalizers is to: - provide description of valid option values - check format and preprocess values passed by users - offer value completion

Every normalizer must be descendant of HammerCLI::Options::Normalizers::AbstractNormalizer.

Example usage:

option "--enabled", "ENABLED", "Should the host be enabled?",
  :format => HammerCLI::Options::Normalizers::Bool.new

Description of valid values

There is a method description that should return a help string. It’s value is used in the output of -h, which can then look for example like this:

--enabled ENABLED             Should the host be enabled?
                              One of true/false, yes/no, 1/0.

Abstract normalizer returns an empty string by default.

Check and format passed values

Normalizer’s method format is used for such checks. The method behaves as a filter taking a string value as it’s input and returning a value of any type.

If the value is not valid, ArgumentError with an appropriate message should be risen. Implementation in Bool normalizer is a good example of such functionality:

def format(bool)
  bool = bool.to_s
  if bool.downcase.match(/^(true|t|yes|y|1)$/i)
    return true
  elsif bool.downcase.match(/^(false|f|no|n|0)$/i)
    return false
  else
    raise ArgumentError, "value must be one of true/false, yes/no, 1/0"
  end
end

Note: the format is not called when NIL (value reserved for nil) is used.

Value completion

Normalizers can also provide completion of option values via method complete. It takes one argument - the current option value at the time the completion was requested. In the simplest cases the method returns array of all possible values. More complex completions can use the current value argument for building the return values.

We distinguish two types of offered completion strings:

Terminal completions - used in most cases - the value is terminal and the completion finishes when it is selected - terminal strings have to end with a blank space

Partial complations - used to offer completion pieces, eg. directory names when completing file path - the completion continues until a terminal string is selected - the values have to end with any character but blank space

Completing file paths demonstrate the difference nicely:

# "hammer some command --file /etc/f"
file_normalizer.complete("/etc/f")
[
  "/etc/foreman/", # partial completion, can continue with the directory contents
  "/etc/foo/",     # -- || --
  "/etc/foo.conf " # terminal, the completion can't continue
]

Example of a simple completion method for boolean values:

def complete(value)
  ["yes ", "no "]
end

Example of a method completing file paths:

def complete(value)
  Dir[value.to_s+'*'].collect do |file|
    if ::File.directory?(file)
      file+'/'
    else
      file+' '
    end
  end
end

See more examples in normalizers.rb.