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
Returns the effective acceptor. @return [Toys::Acceptor::Base]
Returns the default value, which may be `nil`. @return [Object]
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]
The display name of this flag. @return [String]
The proc that determines shell completions for the flag. @return [Proc,Toys::Completion::Base]
Returns an array of Flag::Syntax
for the flags. @return [Array<Toys::Flag::Syntax>]
The type of flag.
@return [:boolean] if the flag is a simple boolean switch @return [:value] if the flag sets a value
Returns the flag group containing this flag @return [Toys::FlagGroup]
The handler for setting/updating the value. @return [Proc]
Returns the key. @return [Symbol]
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>]
A string that can be used to sort this flag @return [String]
The proc that determines shell completions for the value. @return [Proc,Toys::Completion::Base]
The value delimiter, which may be `“”`, `“ ”`, or `“=”`.
@return [String] The delimiter @return [nil] if the flag type is not `:value`.
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`.
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 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
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
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 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
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
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
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
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
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
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
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
# 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
# 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
# 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
# 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
# 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
# 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
# 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