class Toys::Flag

Representation of a formal set of flags that set a particular context key. The flags within a single Flag definition are synonyms.

Constants

DEFAULT_HANDLER

The default handler is the set handler, replacing the previous value. @return [Proc]

PUSH_HANDLER

The push handler pushes the given value using the `<<` operator. @return [Proc]

SET_HANDLER

The set handler replaces the previous value. @return [Proc]

Attributes

acceptor[R]

Returns the effective acceptor. @return [Toys::Acceptor::Base]

default[R]

Returns the default value, which may be `nil`. @return [Object]

desc[R]

The short description string.

When reading, this is always returned as a {Toys::WrappableString}.

When setting, the description may be provided as any of the following:

*  A {Toys::WrappableString}.
*  A normal String, which will be transformed into a
   {Toys::WrappableString} using spaces as word delimiters.
*  An Array of String, which will be transformed into a
   {Toys::WrappableString} where each array element represents an
   individual word for wrapping.

@return [Toys::WrappableString]

display_name[R]

The display name of this flag. @return [String]

flag_completion[R]

The proc that determines shell completions for the flag. @return [Proc,Toys::Completion::Base]

flag_syntax[R]

Returns an array of Flag::Syntax for the flags. @return [Array<Toys::Flag::Syntax>]

flag_type[R]

The type of flag.

@return [:boolean] if the flag is a simple boolean switch @return [:value] if the flag sets a value

group[R]

Returns the flag group containing this flag @return [Toys::FlagGroup]

handler[R]

The handler for setting/updating the value. @return [Proc]

key[R]

Returns the key. @return [Symbol]

long_desc[R]

The long description strings.

When reading, this is returned as an Array of {Toys::WrappableString} representing the lines in the description.

When setting, the description must be provided as an Array where *each element* may be any of the following:

*  A {Toys::WrappableString} representing one line.
*  A normal String representing a line. This will be transformed into a
   {Toys::WrappableString} using spaces as word delimiters.
*  An Array of String representing a line. This will be transformed into
   a {Toys::WrappableString} where each array element represents an
   individual word for wrapping.

@return [Array<Toys::WrappableString>]

sort_str[R]

A string that can be used to sort this flag @return [String]

value_completion[R]

The proc that determines shell completions for the value. @return [Proc,Toys::Completion::Base]

value_delim[R]

The value delimiter, which may be `“”`, `“ ”`, or `“=”`.

@return [String] The delimiter @return [nil] if the flag type is not `:value`.

value_label[R]

The string label for the value as it should display in help. @return [String] The label @return [nil] if the flag type is not `:value`.

value_type[R]

The type of value.

@return [:required] if the flag type is `:value` and the value is

required.

@return [:optional] if the flag type is `:value` and the value is

optional.

@return [nil] if the flag type is not `:value`.

Public Class Methods

create(key, flags = [], used_flags: nil, report_collisions: true, accept: nil, handler: nil, default: nil, complete_flags: nil, complete_values: nil, display_name: nil, desc: nil, long_desc: nil, group: nil) click to toggle source

Create a flag definition.

@param key [String,Symbol] The key to use to retrieve the value from

the execution context.

@param flags [Array<String>] The flags in OptionParser format. If empty,

a flag will be inferred from the key.

@param accept [Object] An acceptor that validates and/or converts the

value. See {Toys::Acceptor.create} for recognized formats. Optional.
If not specified, defaults to {Toys::Acceptor::DEFAULT}.

@param default [Object] The default value. This is the value that will

be set in the context if this flag is not provided on the command
line. Defaults to `nil`.

@param handler [Proc,nil,:set,:push] An optional handler for

setting/updating the value. A handler is a proc taking two
arguments, the given value and the previous value, returning the
new value that should be set. You may also specify a predefined
named handler. The `:set` handler (the default) replaces the
previous value (effectively `-> (val, _prev) { val }`). The
`:push` handler expects the previous value to be an array and
pushes the given value onto it; it should be combined with setting
`default: []` and is intended for "multi-valued" flags.

@param complete_flags [Object] A specifier for shell tab completion for

flag names associated with this flag. By default, a
{Toys::Flag::DefaultCompletion} is used, which provides the flag's
names as completion candidates. To customize completion, set this to
a hash of options to pass to the constructor for
{Toys::Flag::DefaultCompletion}, or pass any other spec recognized
by {Toys::Completion.create}.

@param complete_values [Object] A specifier for shell tab completion for

flag values associated with this flag. Pass any spec recognized by
{Toys::Completion.create}.

@param report_collisions [Boolean] Raise an exception if a flag is

requested that is already in use or marked as disabled. Default is
true.

@param group [Toys::FlagGroup] Group containing this flag. @param desc [String,Array<String>,Toys::WrappableString] Short

description for the flag. See {Toys::ToolDefinition#desc} for a
description of allowed formats. Defaults to the empty string.

@param long_desc [Array<String,Array<String>,Toys::WrappableString>]

Long description for the flag. See {Toys::ToolDefinition#long_desc}
for a description of allowed formats. Defaults to the empty array.

@param display_name [String] A display name for this flag, used in help

text and error messages.

@param used_flags [Array<String>] An array of flags already in use.

# File lib/toys/flag.rb, line 97
def self.create(key, flags = [],
                used_flags: nil, report_collisions: true, accept: nil, handler: nil,
                default: nil, complete_flags: nil, complete_values: nil, display_name: nil,
                desc: nil, long_desc: nil, group: nil)
  new(key, flags, used_flags, report_collisions, accept, handler, default, complete_flags,
      complete_values, desc, long_desc, display_name, group)
end
new(key, flags, used_flags, report_collisions, acceptor, handler, default, flag_completion, value_completion, desc, long_desc, display_name, group) click to toggle source

Create a Flag definition. This argument list is subject to change. Use {Toys::Flag.create} instead for a more stable interface. @private

# File lib/toys/flag.rb, line 33
def initialize(key, flags, used_flags, report_collisions, acceptor, handler, default,
               flag_completion, value_completion, desc, long_desc, display_name, group)
  @group = group
  @key = key
  @flag_syntax = Array(flags).map { |s| Syntax.new(s) }
  @acceptor = Acceptor.create(acceptor)
  @handler = resolve_handler(handler)
  @desc = WrappableString.make(desc)
  @long_desc = WrappableString.make_array(long_desc)
  @default = default
  @flag_completion = create_flag_completion(flag_completion)
  @value_completion = Completion.create(value_completion, **{})
  create_default_flag if @flag_syntax.empty?
  remove_used_flags(used_flags, report_collisions)
  canonicalize
  summarize(display_name)
end

Public Instance Methods

active?() click to toggle source

Whether this flag is active–that is, it has a nonempty flags list.

@return [Boolean]

# File lib/toys/flag.rb, line 297
def active?
  !effective_flags.empty?
end
append_long_desc(long_desc) click to toggle source

Append long description strings.

You must pass an array of lines in the long description. See {#long_desc} for details on how each line may be represented.

@param long_desc [Array<Toys::WrappableString,String,Array<String>>] @return [self]

# File lib/toys/flag.rb, line 332
def append_long_desc(long_desc)
  @long_desc.concat(WrappableString.make_array(long_desc))
  self
end
canonical_syntax_strings() click to toggle source

A list of canonical flag syntax strings.

@return [Array<String>]

# File lib/toys/flag.rb, line 288
def canonical_syntax_strings
  @canonical_syntax_strings ||= flag_syntax.map(&:canonical_str)
end
desc=(desc) click to toggle source

Set the short description string.

See {#desc} for details.

@param desc [Toys::WrappableString,String,Array<String>]

# File lib/toys/flag.rb, line 308
def desc=(desc)
  @desc = WrappableString.make(desc)
end
effective_flags() click to toggle source

The list of all effective flags used. @return [Array<String>]

# File lib/toys/flag.rb, line 255
def effective_flags
  @effective_flags ||= flag_syntax.flat_map(&:flags)
end
long_desc=(long_desc) click to toggle source

Set the long description strings.

See {#long_desc} for details.

@param long_desc [Array<Toys::WrappableString,String,Array<String>>]

# File lib/toys/flag.rb, line 319
def long_desc=(long_desc)
  @long_desc = WrappableString.make_array(long_desc)
end
long_flag_syntax() click to toggle source

An array of Flag::Syntax including only long (double-dash) flags. @return [Array<Flag::Syntax>]

# File lib/toys/flag.rb, line 247
def long_flag_syntax
  @long_flag_syntax ||= flag_syntax.find_all { |ss| ss.flag_style == :long }
end
resolve(str) click to toggle source

Look up the flag by string. Returns an object that indicates whether the given string matched this flag, whether the match was unique, and other pertinent information.

@param str [String] Flag string to look up @return [Toys::Flag::Resolution] Information about the match.

# File lib/toys/flag.rb, line 267
def resolve(str)
  resolution = Resolution.new(str)
  flag_syntax.each do |fs|
    if fs.positive_flag == str
      resolution.add!(self, fs, false, true)
    elsif fs.negative_flag == str
      resolution.add!(self, fs, true, true)
    elsif fs.positive_flag.start_with?(str)
      resolution.add!(self, fs, false, false)
    elsif fs.negative_flag.to_s.start_with?(str)
      resolution.add!(self, fs, true, false)
    end
  end
  resolution
end
short_flag_syntax() click to toggle source

An array of Flag::Syntax including only short (single dash) flags. @return [Array<Flag::Syntax>]

# File lib/toys/flag.rb, line 239
def short_flag_syntax
  @short_flag_syntax ||= flag_syntax.find_all { |ss| ss.flag_style == :short }
end

Private Instance Methods

analyze_flag_syntax(flag) click to toggle source
# File lib/toys/flag.rb, line 418
def analyze_flag_syntax(flag)
  return if flag.flag_type.nil?
  if !@flag_type.nil? && @flag_type != flag.flag_type
    raise ToolDefinitionError, "Cannot have both value and boolean flags for #{key.inspect}"
  end
  @flag_type = flag.flag_type
  return unless @flag_type == :value
  if !@value_type.nil? && @value_type != flag.value_type
    raise ToolDefinitionError,
          "Cannot have both required and optional values for flag #{key.inspect}"
  end
  @value_type = flag.value_type
  @value_label = flag.value_label
  @value_delim = flag.value_delim
end
canonicalize() click to toggle source
# File lib/toys/flag.rb, line 400
def canonicalize
  @flag_type = nil
  @value_type = nil
  @value_label = nil
  @value_delim = " "
  short_flag_syntax.reverse_each do |flag|
    analyze_flag_syntax(flag)
  end
  long_flag_syntax.reverse_each do |flag|
    analyze_flag_syntax(flag)
  end
  @flag_type ||= :boolean
  @value_type ||= :required if @flag_type == :value
  flag_syntax.each do |flag|
    flag.configure_canonical(@flag_type, @value_type, @value_label, @value_delim)
  end
end
create_default_flag() click to toggle source
# File lib/toys/flag.rb, line 367
def create_default_flag
  key_str = key.to_s
  flag_str =
    if key_str.length == 1
      "-#{key_str}" if key_str =~ /[a-zA-Z0-9?]/
    elsif key_str.length > 1
      key_str = key_str.downcase.tr("_", "-").gsub(/[^a-z0-9-]/, "").sub(/^-+/, "")
      "--#{key_str}" unless key_str.empty?
    end
  if flag_str
    needs_val = @value_completion != Completion::EMPTY ||
                ![::Object, ::TrueClass, ::FalseClass].include?(@acceptor.well_known_spec) ||
                ![nil, true, false].include?(@default)
    flag_str = "#{flag_str} VALUE" if needs_val
    @flag_syntax << Syntax.new(flag_str)
  end
end
create_flag_completion(spec) click to toggle source
# File lib/toys/flag.rb, line 354
def create_flag_completion(spec)
  spec =
    case spec
    when nil, :default
      {"": DefaultCompletion, flag: self}
    when ::Hash
      spec[:""].nil? ? spec.merge({"": DefaultCompletion, flag: self}) : spec
    else
      spec
    end
  Completion.create(spec, **{})
end
remove_used_flags(used_flags, report_collisions) click to toggle source
# File lib/toys/flag.rb, line 385
def remove_used_flags(used_flags, report_collisions)
  return if !used_flags && !report_collisions
  @flag_syntax.select! do |fs|
    fs.flags.all? do |f|
      collision = used_flags&.include?(f)
      if collision && report_collisions
        raise ToolDefinitionError,
              "Cannot use flag #{f.inspect} because it is already assigned or reserved."
      end
      !collision
    end
  end
  used_flags&.concat(effective_flags.uniq)
end
resolve_handler(handler) click to toggle source
# File lib/toys/flag.rb, line 339
def resolve_handler(handler)
  case handler
  when ::Proc
    handler
  when nil, :default
    DEFAULT_HANDLER
  when :set
    SET_HANDLER
  when :push, :append
    PUSH_HANDLER
  else
    raise ToolDefinitionError, "Unknown handler: #{handler.inspect}"
  end
end
summarize(name) click to toggle source
# File lib/toys/flag.rb, line 434
def summarize(name)
  @display_name =
    name ||
    long_flag_syntax.first&.canonical_str ||
    short_flag_syntax.first&.canonical_str ||
    key.to_s
  @sort_str =
    long_flag_syntax.first&.sort_str ||
    short_flag_syntax.first&.sort_str ||
    ""
end