Module: Toys::DSL::Tool

Defined in:
lib/toys/dsl/tool.rb

Overview

This module defines the DSL for a Toys configuration file.

A Toys configuration defines one or more named tools. It provides syntax for setting the description, defining flags and arguments, specifying how to execute the tool, and requesting mixin modules and other services. It also lets you define subtools, nested arbitrarily deep, using blocks.

Simple example

Create a file called .toys.rb in the current directory, with the following contents:

tool "greet" do
  desc "Prints a simple greeting"

  optional_arg :recipient, default: "world"

  def run
    puts "Hello, #{recipient}!"
  end
end

The DSL directives tool, desc, optional_arg, and others are defined in this module.

Now you can execute it using:

toys greet

or try:

toys greet rubyists

Instance Method Summary collapse

Instance Method Details

#acceptor(name, spec = nil, type_desc: nil, &block) ⇒ self

Create a named acceptor that can be referenced by name from any flag or positional argument in this tool or its subtools.

An acceptor validates the string parameter passed to a flag or positional argument. It also optionally converts the string to a different object before storing it in your tool's data.

Acceptors can be defined in one of four ways.

  • You can provide a regular expression. This acceptor validates only if the regex matches the entire string parameter.

    You can also provide an optional conversion function as a block. If provided, function must take a variable number of arguments, the first being the matched string and the remainder being the captures from the regular expression. It should return the converted object that will be stored in the context data. If you do not provide a block, the original string will be used.

  • You can provide an array of possible values. The acceptor validates if the string parameter matches the string form of one of the array elements (i.e. the results of calling to_s on the array elements.)

    An array acceptor automatically converts the string parameter to the actual array element that it matched. For example, if the symbol :foo is in the array, it will match the string "foo", and then store the symbol :foo in the tool data.

  • You can provide a range of possible values, along with a conversion function that converts a string parameter to a type comparable by the range. (See the "function" spec below for a detailed description of conversion functions.) If the range has numeric endpoints, the conversion function is optional because a default will be provided.

  • You can provide a function by passing it as a proc or a block. This function performs both validation and conversion. It should take the string parameter as its argument, and it must either return the object that should be stored in the tool data, or raise an exception (descended from StandardError) to indicate that the string parameter is invalid.

Example

The following example creates an acceptor named "hex" that is defined via a regular expression. It uses the acceptor to validate values passed to a flag.

tool "example" do
  acceptor "hex", /[0-9a-fA-F]+/, type_desc: "hex numbers"
  flag :number, accept: "hex"
  def run
    puts "number was #{number}"
  end
end

Parameters:

  • name (String)

    The acceptor name.

  • spec (Object) (defaults to: nil)

    See the description for recognized values.

  • type_desc (String) (defaults to: nil)

    Type description string, shown in help. Defaults to the acceptor name.

  • block (Proc)

    See the description for recognized forms.

Returns:

  • (self)


105
106
107
108
109
# File 'lib/toys/dsl/tool.rb', line 105

def acceptor(name, spec = nil, type_desc: nil, &block)
  cur_tool = DSL::Internal.current_tool(self, false)
  cur_tool&.add_acceptor(name, spec, type_desc: type_desc || name.to_s, &block)
  self
end

#alias_tool(word, target) ⇒ self

Deprecated.

Use #tool and pass :delegate_relative instead

Create an alias, representing an "alternate name" for a tool.

Note: This is functionally equivalent to creating a tool with the :delegate_relative option. As such, alias_tool is considered deprecated.

Example

This example defines a tool and an alias pointing to it. Both the tool name test and the alias t will then refer to the same tool.

tool "test" do
  def run
    puts "Running tests..."
  end
end
alias_tool "t", "test"
# Note: the following is preferred over alias_tool:
# tool "t", delegate_relative: "test"

Parameters:

  • word (String)

    The name of the alias

  • target (String, Array<String>)

    Relative path to the target of the alias. This path may be given as an array of strings, or a single string possibly delimited by path separators.

Returns:

  • (self)


368
369
370
371
# File 'lib/toys/dsl/tool.rb', line 368

def alias_tool(word, target)
  tool(word, delegate_relative: target)
  self
end

#all_required(desc: nil, long_desc: nil, name: nil, report_collisions: true, prepend: false, &block) ⇒ self

Create a flag group of type :required. If a block is given, flags defined in the block belong to the group. All flags in this group are required.

Example

The following example creates a group of required flags.

tool "login" do
  all_required do
    flag :username, "--username=VAL", desc: "Set username (required)"
    flag :password, "--password=VAL", desc: "Set password (required)"
  end
  # ...
end

Parameters:

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the group. See #desc for a description of allowed formats. Defaults to "Flags".

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag group. See #long_desc for a description of allowed formats. Defaults to the empty array.

  • name (String, Symbol, nil) (defaults to: nil)

    The name of the group, or nil for no name.

  • report_collisions (Boolean) (defaults to: true)

    If true, raise an exception if a the given name is already taken. If false, ignore. Default is true.

  • prepend (Boolean) (defaults to: false)

    If true, prepend rather than append the group to the list. Default is false.

  • block (Proc)

    Adds flags to the group. See FlagGroup for the directives that can be called in this block.

Returns:

  • (self)


717
718
719
720
721
# File 'lib/toys/dsl/tool.rb', line 717

def all_required(desc: nil, long_desc: nil, name: nil, report_collisions: true,
                 prepend: false, &block)
  flag_group(type: :required, desc: desc, long_desc: long_desc,
             name: name, report_collisions: report_collisions, prepend: prepend, &block)
end

#at_least_one(desc: nil, long_desc: nil, name: nil, report_collisions: true, prepend: false, &block) ⇒ self Also known as: at_least_one_required

Create a flag group of type :at_least_one. If a block is given, flags defined in the block belong to the group. At least one flag in this group must be provided on the command line.

Example

The following example creates a group of flags in which one or more may be set.

tool "run-tests" do
  at_least_one do
    flag :unit, desc: "Run unit tests"
    flag :integration, desc: "Run integration tests"
    flag :performance, desc: "Run performance tests"
  end
  # ...
end

Parameters:

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the group. See #desc for a description of allowed formats. Defaults to "Flags".

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag group. See #long_desc for a description of allowed formats. Defaults to the empty array.

  • name (String, Symbol, nil) (defaults to: nil)

    The name of the group, or nil for no name.

  • report_collisions (Boolean) (defaults to: true)

    If true, raise an exception if a the given name is already taken. If false, ignore. Default is true.

  • prepend (Boolean) (defaults to: false)

    If true, prepend rather than append the group to the list. Default is false.

  • block (Proc)

    Adds flags to the group. See FlagGroup for the directives that can be called in this block.

Returns:

  • (self)


804
805
806
807
808
# File 'lib/toys/dsl/tool.rb', line 804

def at_least_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
                 prepend: false, &block)
  flag_group(type: :at_least_one, desc: desc, long_desc: long_desc,
             name: name, report_collisions: report_collisions, prepend: prepend, &block)
end

#at_most_one(desc: nil, long_desc: nil, name: nil, report_collisions: true, prepend: false, &block) ⇒ self Also known as: at_most_one_required

Create a flag group of type :at_most_one. If a block is given, flags defined in the block belong to the group. At most one flag in this group must be provided on the command line.

Example

The following example creates a group of flags in which either one or none may be set, but not more than one.

tool "provision-server" do
  at_most_one do
    flag :restore_from_backup, "--restore-from-backup=VAL"
    flag :restore_from_image, "--restore-from-image=VAL"
    flag :clone_existing, "--clone-existing=VAL"
  end
  # ...
end

Parameters:

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the group. See #desc for a description of allowed formats. Defaults to "Flags".

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag group. See #long_desc for a description of allowed formats. Defaults to the empty array.

  • name (String, Symbol, nil) (defaults to: nil)

    The name of the group, or nil for no name.

  • report_collisions (Boolean) (defaults to: true)

    If true, raise an exception if a the given name is already taken. If false, ignore. Default is true.

  • prepend (Boolean) (defaults to: false)

    If true, prepend rather than append the group to the list. Default is false.

  • block (Proc)

    Adds flags to the group. See FlagGroup for the directives that can be called in this block.

Returns:

  • (self)


760
761
762
763
764
# File 'lib/toys/dsl/tool.rb', line 760

def at_most_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
                prepend: false, &block)
  flag_group(type: :at_most_one, desc: desc, long_desc: long_desc,
             name: name, report_collisions: report_collisions, prepend: prepend, &block)
end

#complete_tool_args(spec = nil, **options, &block) ⇒ self

Set the shell completion strategy for this tool's arguments. You can pass one of the following:

Example

The namespace "foo" supports completion only of subtool names. It does not complete the standard flags (like --help).

tool "foo" do
  complete_tool_args complete_args: false, complete_flags: false,
                     complete_flag_values: false
  tool "bar" do
    def run
      puts "in foo bar"
    end
  end
end

Parameters:

  • spec (Object) (defaults to: nil)
  • options (Hash)
  • block (Proc)

Returns:

  • (self)


1479
1480
1481
1482
1483
1484
# File 'lib/toys/dsl/tool.rb', line 1479

def complete_tool_args(spec = nil, **options, &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  cur_tool.completion = Completion.scalarize_spec(spec, options, block)
  self
end

#completion(name, spec = nil, **options, &block) ⇒ self

Create a named completion procedure that may be used by name by any flag or positional arg in this tool or any subtool.

A completion controls tab completion for the value of a flag or positional argument. In general, it is a Ruby Proc that takes a context object (of type Completion::Context) and returns an array of completion candidate strings.

Completions can be specified in one of three ways.

  • A Proc object itself, either passed directly to this directive or provided as a block.
  • A static array of strings, indicating the completion candidates independent of context.
  • The symbol :file_system which indicates that paths in the file system should serve as completion candidates.

Example

The following example defines a completion that uses only the immediate files in the current directory as candidates. (This is different from the :file_system completion which will descend into subdirectories similar to how bash completes most of its file system commands.)

completion "local-files" do |_context|
  `/bin/ls`.split("\n")
end
tool "example" do
  flag :file, complete_values: "local-files"
  def run
    puts "selected file #{file}"
  end
end

Parameters:

  • name (String)

    Name of the completion

  • spec (Object) (defaults to: nil)

    See the description for recognized values.

  • options (Hash)

    Additional options to pass to the completion.

  • block (Proc)

    See the description for recognized forms.

Returns:

  • (self)


259
260
261
262
263
264
# File 'lib/toys/dsl/tool.rb', line 259

def completion(name, spec = nil, **options, &block)
  cur_tool = DSL::Internal.current_tool(self, false)
  return self if cur_tool.nil?
  cur_tool.add_completion(name, spec, **options, &block)
  self
end

#context_directoryString?

Return the context directory for this tool. Generally, this defaults to the directory containing the toys config directory structure being read, but it may be changed by setting a different context directory for the tool.

Returns:

  • (String)

    Context directory path

  • (nil)

    if there is no context.



1738
1739
1740
1741
# File 'lib/toys/dsl/tool.rb', line 1738

def context_directory
  cur_tool = DSL::Internal.current_tool(self, false)
  cur_tool&.context_directory || source_info.context_directory
end

#current_toolToys::ToolDefinition

Return the current tool config. This object can be queried to determine such information as the name, but it should not be altered.



1749
1750
1751
# File 'lib/toys/dsl/tool.rb', line 1749

def current_tool
  DSL::Internal.current_tool(self, false)
end

#delegate_to(target) ⇒ self

Causes the current tool to delegate to another tool, specified by the full tool name. When run, it simply invokes the target tool with the same arguments.

Example

This example defines a tool that runs one of its subtools. Running the test tool will have the same effect (and recognize the same args) as the subtool test unit.

tool "test" do
  tool "unit" do
    flag :faster
    def run
      puts "running tests..."
    end
  end
  delegate_to "test:unit"
end

Parameters:

  • target (String, Array<String>)

    The full path to the delegate tool. This path may be given as an array of strings, or a single string possibly delimited by path separators.

Returns:

  • (self)


399
400
401
402
403
404
# File 'lib/toys/dsl/tool.rb', line 399

def delegate_to(target)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  cur_tool.delegate_to(@__loader.split_path(target))
  self
end

#desc(str) ⇒ self Also known as: short_desc

Set the short description for the current tool. The short description is displayed with the tool in a subtool list. You may also use the equivalent method short_desc.

The description is a WrappableString, which may be word-wrapped when displayed in a help screen. You may pass a WrappableString directly to this method, or you may pass any input that can be used to construct a wrappable string:

  • If you pass a String, its whitespace will be compacted (i.e. tabs, newlines, and multiple consecutive whitespace will be turned into a single space), and it will be word-wrapped on whitespace.
  • If you pass an Array of Strings, each string will be considered a literal word that cannot be broken, and wrapping will be done across the strings in the array. In this case, whitespace is not compacted.

Examples

If you pass in a sentence as a simple string, it may be word wrapped when displayed:

desc "This sentence may be wrapped."

To specify a sentence that should never be word-wrapped, pass it as the sole element of a string array:

desc ["This sentence will not be wrapped."]

Parameters:

Returns:

  • (self)


578
579
580
581
582
583
# File 'lib/toys/dsl/tool.rb', line 578

def desc(str)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  cur_tool.desc = str
  self
end

#disable_argument_parsingself

Disable argument parsing for this tool. Arguments will not be parsed and the options will not be populated. Instead, tools can retrieve the full unparsed argument list by calling Context#args.

This directive is mutually exclusive with any of the directives that declare arguments or flags.

Example

tool "mytool" do
  disable_argument_parsing
  def run
    puts "Arguments passed: #{args}"
  end
end

Returns:

  • (self)


1413
1414
1415
1416
1417
# File 'lib/toys/dsl/tool.rb', line 1413

def disable_argument_parsing
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.disable_argument_parsing
  self
end

#disable_flag(*flags) ⇒ self

Mark one or more flags as disabled, preventing their use by any subsequent flag definition. This can be used to prevent middleware from defining a particular flag.

Example

This tool does not support the -v and -q short forms for the two verbosity flags (although it still supports the long forms --verbose and --quiet.)

tool "mytool" do
  disable_flag "-v", "-q"
  def run
    # ...
  end
end

Parameters:

  • flags (String...)

    The flags to disable

Returns:

  • (self)


1440
1441
1442
1443
1444
# File 'lib/toys/dsl/tool.rb', line 1440

def disable_flag(*flags)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.disable_flag(*flags)
  self
end

#enforce_flags_before_args(state = true) ⇒ self

Enforce that all flags must be provided before any positional args. That is, as soon as the first positional arg appears in the command line arguments, flag parsing is disabled as if -- had appeared.

Issuing this directive by itself turns on enforcement. You may turn it off by passsing false as the parameter.

Parameters:

  • state (Boolean) (defaults to: true)

Returns:

  • (self)


1371
1372
1373
1374
1375
# File 'lib/toys/dsl/tool.rb', line 1371

def enforce_flags_before_args(state = true)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.enforce_flags_before_args(state)
  self
end

#exactly_one(desc: nil, long_desc: nil, name: nil, report_collisions: true, prepend: false, &block) ⇒ self Also known as: exactly_one_required

Create a flag group of type :exactly_one. If a block is given, flags defined in the block belong to the group. Exactly one flag in this group must be provided on the command line.

Example

The following example creates a group of flags in which exactly one must be set.

tool "deploy" do
  exactly_one do
    flag :server, "--server=IP_ADDR", desc: "Deploy to server"
    flag :vm, "--vm=ID", desc: "Deploy to a VM"
    flag :container, "--container=ID", desc: "Deploy to a container"
  end
  # ...
end

Parameters:

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the group. See #desc for a description of allowed formats. Defaults to "Flags".

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag group. See #long_desc for a description of allowed formats. Defaults to the empty array.

  • name (String, Symbol, nil) (defaults to: nil)

    The name of the group, or nil for no name.

  • report_collisions (Boolean) (defaults to: true)

    If true, raise an exception if a the given name is already taken. If false, ignore. Default is true.

  • prepend (Boolean) (defaults to: false)

    If true, prepend rather than append the group to the list. Default is false.

  • block (Proc)

    Adds flags to the group. See FlagGroup for the directives that can be called in this block.

Returns:

  • (self)


848
849
850
851
852
# File 'lib/toys/dsl/tool.rb', line 848

def exactly_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
                prepend: false, &block)
  flag_group(type: :exactly_one, desc: desc, long_desc: long_desc,
             name: name, report_collisions: report_collisions, prepend: prepend, &block)
end

#expand(template_class, *args, **kwargs) {|template| ... } ⇒ self

Expand the given template in the current location.

The template may be specified as a class or a well-known template name. You may also provide arguments to pass to the template.

Example

The following example creates and uses a simple template.

template "hello-generator" do
  def initialize(name, message)
    @name = name
    @message = message
  end
  attr_reader :name, :message
  expansion do |template|
    tool template.name do
      to_run do
        puts template.message
      end
    end
  end
end

expand "hello-generator", "mytool", "mytool is running!"

Parameters:

  • template_class (Class, String, Symbol)

    The template, either as a class or a well-known name.

  • args (Object...)

    Template arguments

Yields:

Returns:

  • (self)


526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/toys/dsl/tool.rb', line 526

def expand(template_class, *args, **kwargs)
  cur_tool = DSL::Internal.current_tool(self, false)
  return self if cur_tool.nil?
  name = template_class.to_s
  case template_class
  when ::String
    template_class = cur_tool.lookup_template(template_class)
  when ::Symbol
    template_class = @__loader.resolve_standard_template(name)
  end
  if template_class.nil?
    raise ToolDefinitionError, "Template not found: #{name.inspect}"
  end
  template = template_class.new(*args, **kwargs)
  yield template if block_given?
  class_exec(template, &template_class.expansion)
  self
end

#find_data(path, type: nil) ⇒ String?

Find the given data path (file or directory).

Data directories are a convenient place to put images, archives, keys, or other such static data needed by your tools. Data files are located in a directory called .data inside a Toys directory. This directive locates a data file during tool definition.

Example

This tool reads its description from a text file in the .data directory.

tool "mytool" do
  path = find_data("mytool-desc.txt", type: :file)
  desc IO.read(path) if path
  def run
    # ...
  end
end

Parameters:

  • path (String)

    The path to find

  • type (nil, :file, :directory) (defaults to: nil)

    Type of file system object to find. Default is nil, indicating any type.

Returns:

  • (String)

    Absolute path of the data.

  • (nil)

    if the given data path is not found.



1725
1726
1727
# File 'lib/toys/dsl/tool.rb', line 1725

def find_data(path, type: nil)
  source_info.find_data(path, type: type)
end

#flag(key, *flags, accept: nil, default: nil, handler: nil, complete_flags: nil, complete_values: nil, report_collisions: true, group: nil, desc: nil, long_desc: nil, display_name: nil, add_method: nil, &block) ⇒ self

Add a flag to the current tool. Each flag must specify a key which the script may use to obtain the flag value from the context. You may then provide the flags themselves in OptionParser form.

If the given key is a symbol representing a valid method name, then a helper method is automatically added to retrieve the value. Otherwise, if the key is a string or does not represent a valid method name, the tool can retrieve the value by calling Context#get.

Attributes of the flag may be passed in as arguments to this method, or set in a block passed to this method. If you provide a block, you can use directives in Flag within the block.

Flag syntax

The flags themselves should be provided in OptionParser form. Following are examples of valid syntax.

  • -a : A short boolean switch. When this appears as an argument, the value is set to true.
  • --abc : A long boolean switch. When this appears as an argument, the value is set to true.
  • -aVAL or -a VAL : A short flag that takes a required value. These two forms are treated identically. If this argument appears with a value attached (e.g. -afoo), the attached string (e.g. "foo") is taken as the value. Otherwise, the following argument is taken as the value (e.g. for -a foo, the value is set to "foo".) The following argument is treated as the value even if it looks like a flag (e.g. -a -a causes the string "-a" to be taken as the value.)
  • -a[VAL] : A short flag that takes an optional value. If this argument appears with a value attached (e.g. -afoo), the attached string (e.g. "foo") is taken as the value. Otherwise, the value is set to true. The following argument is never interpreted as the value. (Compare with -a [VAL].)
  • -a [VAL] : A short flag that takes an optional value. If this argument appears with a value attached (e.g. -afoo), the attached string (e.g. "foo") is taken as the value. Otherwise, if the following argument does not look like a flag (i.e. it does not begin with a hyphen), it is taken as the value. (e.g. -a foo causes the string "foo" to be taken as the value.). If there is no following argument, or the following argument looks like a flag, the value is set to true. (Compare with -a[VAL].)
  • --abc=VAL or --abc VAL : A long flag that takes a required value. These two forms are treated identically. If this argument appears with a value attached (e.g. --abc=foo), the attached string (e.g. "foo") is taken as the value. Otherwise, the following argument is taken as the value (e.g. for --abc foo, the value is set to "foo".) The following argument is treated as the value even if it looks like a flag (e.g. --abc --def causes the string "--def" to be taken as the value.)
  • --abc[=VAL] : A long flag that takes an optional value. If this argument appears with a value attached (e.g. --abc=foo), the attached string (e.g. "foo") is taken as the value. Otherwise, the value is set to true. The following argument is never interpreted as the value. (Compare with --abc [VAL].)
  • --abc [VAL] : A long flag that takes an optional value. If this argument appears with a value attached (e.g. --abc=foo), the attached string (e.g. "foo") is taken as the value. Otherwise, if the following argument does not look like a flag (i.e. it does not begin with a hyphen), it is taken as the value. (e.g. --abc foo causes the string "foo" to be taken as the value.). If there is no following argument, or the following argument looks like a flag, the value is set to true. (Compare with --abc=[VAL].)
  • --[no-]abc : A long boolean switch that can be turned either on or off. This effectively creates two flags, --abc which sets the value to true, and --no-abc which sets the falue to false.

Default flag syntax

If no flag syntax strings are provided, a default syntax will be inferred based on the key and other options.

Specifically, if the key has one character, then that character will be chosen as a short flag. If the key has multiple characters, a long flag will be generated.

Furthermore, if a custom completion, a non-boolean acceptor, or a non-boolean default value is provided in the options, then the flag will be considered to take a value. Otherwise, it will be considered to be a boolean switch.

For example, the following pairs of flags are identical:

flag :a
flag :a, "-a"

flag :abc_def
flag :abc_def, "--abc-def"

flag :number, accept: Integer
flag :number, "--number=VAL", accept: Integer

More examples

A flag that sets its value to the number of times it appears on the command line:

flag :verbose, "-v", "--verbose",
     default: 0, handler: ->(_val, count) { count + 1 }

An example using block form:

flag :shout do
  flags "-s", "--shout"
  default false
  desc "Say it louder"
  long_desc "This flag says it lowder.",
            "You might use this when people can't hear you.",
            "",
            "Example:",
            ["    toys say --shout hello"]
end

Parameters:

  • key (String, Symbol)

    The key to use to retrieve the value from the execution context.

  • flags (String...)

    The flags in OptionParser format.

  • accept (Object) (defaults to: nil)

    An acceptor that validates and/or converts the value. You may provide either the name of an acceptor you have defined, one of the default acceptors provided by OptionParser, or any other specification recognized by Acceptor.create. Optional. If not specified, accepts any value as a string.

  • default (Object) (defaults to: nil)

    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.

  • handler (Proc, nil, :set, :push) (defaults to: nil)

    An optional handler that customizes how a value is set or updated when the flag is parsed. A handler is a proc that takes up to three arguments: the given value, the previous value, and a hash containing all the data collected so far during argument parsing. The proc must return the new value for the flag. You may also specify a predefined named handler. The :set handler (the default) replaces the previous value (effectively -> (val) { 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 the default value to [] and is intended for "multi-valued" flags.

  • complete_flags (Object) (defaults to: nil)

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

  • complete_values (Object) (defaults to: nil)

    A specifier for shell tab completion for flag values associated with this flag. This is the empty completion by default. To customize completion, set this to the name of a previously defined completion, or any spec recognized by Completion.create.

  • report_collisions (Boolean) (defaults to: true)

    Raise an exception if a flag is requested that is already in use or marked as unusable. Default is true.

  • group (Toys::FlagGroup, String, Symbol, nil) (defaults to: nil)

    Group for this flag. You may provide a group name, a FlagGroup object, or nil which denotes the default group.

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the flag. See #desc for a description of the allowed formats. Defaults to the empty string.

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag. See #long_desc for a description of the allowed formats. (But note that this param takes an Array of description lines, rather than a series of arguments.) Defaults to the empty array.

  • display_name (String) (defaults to: nil)

    A display name for this flag, used in help text and error messages.

  • add_method (true, false, nil) (defaults to: nil)

    Whether to add a method for this flag. If omitted or set to nil, uses the default behavior, which adds the method if the key is a symbol representing a legal method name that starts with a letter and does not override any public method in the Ruby Object class or collide with any method directly defined in the tool class.

  • block (Proc)

    Configures the flag. See Flag for the directives that can be called in this block.

Returns:

  • (self)


1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
# File 'lib/toys/dsl/tool.rb', line 1031

def flag(key, *flags,
         accept: nil, default: nil, handler: nil,
         complete_flags: nil, complete_values: nil,
         report_collisions: true, group: nil,
         desc: nil, long_desc: nil, display_name: nil, add_method: nil,
         &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  flag_dsl = DSL::Flag.new(
    flags.flatten, accept, default, handler, complete_flags, complete_values,
    report_collisions, group, desc, long_desc, display_name, add_method
  )
  flag_dsl.instance_exec(flag_dsl, &block) if block
  flag_dsl._add_to(cur_tool, key)
  DSL::Internal.maybe_add_getter(self, key, flag_dsl._get_add_method)
  self
end

#flag_group(type: :optional, desc: nil, long_desc: nil, name: nil, report_collisions: true, prepend: false, &block) ⇒ self

Create a flag group. If a block is given, flags defined in the block belong to the group. The flags in the group are listed together in help screens.

Example

The following example creates a flag group in which all flags are optional.

tool "execute" do
  flag_group desc: "Debug Flags" do
    flag :debug, "-D", desc: "Enable debugger"
    flag :warnings, "-W[VAL]", desc: "Enable warnings"
  end
  # ...
end

Parameters:

  • type (Symbol) (defaults to: :optional)

    The type of group. Allowed values: :required, :optional, :exactly_one, :at_most_one, :at_least_one. Default is :optional.

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the group. See #desc for a description of allowed formats. Defaults to "Flags".

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag group. See #long_desc for a description of allowed formats. Defaults to the empty array.

  • name (String, Symbol, nil) (defaults to: nil)

    The name of the group, or nil for no name.

  • report_collisions (Boolean) (defaults to: true)

    If true, raise an exception if a the given name is already taken. If false, ignore. Default is true.

  • prepend (Boolean) (defaults to: false)

    If true, prepend rather than append the group to the list. Default is false.

  • block (Proc)

    Adds flags to the group. See FlagGroup for the directives that can be called in this block.

Returns:

  • (self)


670
671
672
673
674
675
676
677
678
679
680
# File 'lib/toys/dsl/tool.rb', line 670

def flag_group(type: :optional, desc: nil, long_desc: nil, name: nil,
               report_collisions: true, prepend: false, &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  cur_tool.add_flag_group(type: type, desc: desc, long_desc: long_desc, name: name,
                          report_collisions: report_collisions, prepend: prepend)
  group = prepend ? cur_tool.flag_groups.first : cur_tool.flag_groups.last
  flag_group_dsl = DSL::FlagGroup.new(self, cur_tool, group)
  flag_group_dsl.instance_exec(flag_group_dsl, &block) if block
  self
end

#include(mixin, *args, **kwargs) ⇒ self

Specify that the given module should be mixed into this tool, and its methods made available when running the tool.

You can provide either a module, the string name of a mixin that you have defined in this tool or one of its ancestors, or the symbol name of a well-known mixin.

Example

Include the well-known mixin :terminal and perform some terminal magic.

tool "spin" do
  include :terminal
  def run
    # The spinner method is defined by the :terminal mixin.
    spinner(leading_text: "Waiting...", final_text: "\n") do
      sleep 5
    end
  end
end

Parameters:

  • mixin (Module, Symbol, String)

    Module or module name.

  • args (Object...)

    Arguments to pass to the initializer

  • kwargs (keywords)

    Keyword arguments to pass to the initializer

Returns:

  • (self)


1662
1663
1664
1665
1666
1667
1668
# File 'lib/toys/dsl/tool.rb', line 1662

def include(mixin, *args, **kwargs)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  mod = DSL::Internal.resolve_mixin(mixin, cur_tool, @__loader)
  cur_tool.include_mixin(mod, *args, **kwargs)
  self
end

#include?(mod) ⇒ Boolean?

Determine if the given module/mixin has already been included.

You can provide either a module, the string name of a mixin that you have defined in this tool or one of its ancestors, or the symbol name of a well-known mixin.

Parameters:

  • mod (Module, Symbol, String)

    Module or module name.

Returns:

  • (Boolean)

    Whether the mixin is included

  • (nil)

    if the current tool is not active.



1682
1683
1684
1685
1686
# File 'lib/toys/dsl/tool.rb', line 1682

def include?(mod)
  cur_tool = DSL::Internal.current_tool(self, false)
  return if cur_tool.nil?
  super(DSL::Internal.resolve_mixin(mod, cur_tool, @__loader))
end

#load(path, as: nil) ⇒ self

Load another config file or directory, as if its contents were inserted at the current location.

Parameters:

  • path (String)

    The file or directory to load.

  • as (String) (defaults to: nil)

    Load into the given tool/namespace. If omitted, configuration will be loaded into the current namespace.

Returns:

  • (self)


416
417
418
419
420
421
422
423
424
425
# File 'lib/toys/dsl/tool.rb', line 416

def load(path, as: nil)
  if as
    tool(as) do
      load(path)
    end
    return self
  end
  @__loader.load_path(source_info, path, @__words, @__remaining_words, @__priority)
  self
end

#load_gem(name, *versions, version: nil, path: nil, toys_dir: nil, as: nil) ⇒ Object

Load configuration from a gem, as if its contents were inserted at the current location.

Parameters:

  • name (String)

    Name of the gem

  • versions (Array<String>)

    Version requirements for the gem.

  • version (String, Array<String>) (defaults to: nil)

    An alternate way to specify version requirements for the gem.

  • path (String) (defaults to: nil)

    Optional path within the gem to the file or directory to load. Defaults to the root of the gem's toys directory.

  • toys_dir (String) (defaults to: nil)

    Optional override for the gem's toys directory name. If not specified, the default specified by the gem will be used.

  • as (String) (defaults to: nil)

    Load into the given tool/namespace. If omitted, configuration will be loaded into the current namespace.



480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/toys/dsl/tool.rb', line 480

def load_gem(name, *versions, version: nil, path: nil, toys_dir: nil, as: nil)
  version = versions + Array(version)
  if as
    tool(as) do
      load_gem(name, version: version, path: path, toys_dir: toys_dir)
    end
    return self
  end
  path ||= ""
  @__loader.load_gem(source_info, name, version, toys_dir, path,
                     @__words, @__remaining_words, @__priority)
  self
end

#load_git(remote: nil, path: nil, commit: nil, as: nil, update: false) ⇒ self

Load configuration from a public git repository, as if its contents were inserted at the current location.

Parameters:

  • remote (String) (defaults to: nil)

    The URL of the git repository. Defaults to the current repository if already loading from git.

  • path (String) (defaults to: nil)

    The path within the repo to the file or directory to load. Defaults to the root of the repo.

  • commit (String) (defaults to: nil)

    The commit branch, tag, or sha. Defaults to the current commit if already loading from git, or to HEAD.

  • as (String) (defaults to: nil)

    Load into the given tool/namespace. If omitted, configuration will be loaded into the current namespace.

  • update (Boolean, Integer) (defaults to: false)

    Whether and when to force-fetch from the remote (unless the commit is a SHA). Force-fetching will ensure that symbolic commits, such as branch names or HEAD, are up to date. You can pass true or false to specify whether to update, or an integer to update if the last update was done at least that many seconds ago. Default is false.

Returns:

  • (self)

Raises:



448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/toys/dsl/tool.rb', line 448

def load_git(remote: nil, path: nil, commit: nil, as: nil, update: false)
  if as
    tool(as) do
      load_git(remote: remote, path: path, commit: commit)
    end
    return self
  end
  remote ||= source_info.git_remote
  raise ToolDefinitionError, "Git remote not specified" unless remote
  path ||= ""
  commit ||= source_info.git_commit || "HEAD"
  @__loader.load_git(source_info, remote, path, commit, update,
                     @__words, @__remaining_words, @__priority)
  self
end

#long_desc(*strs, file: nil, data: nil) ⇒ self

Add to the long description for the current tool. The long description is displayed in the usage documentation for the tool itself. This directive may be given multiple times, and the results are cumulative.

A long description is a series of descriptions, which are generally displayed in a series of lines/paragraphs. Each individual description uses the form described in the #desc documentation, and may be word-wrapped when displayed. To insert a blank line, include an empty string as one of the descriptions.

Example

long_desc "This initial paragraph might get word wrapped.",
          "This next paragraph is followed by a blank line.",
          "",
          ["This line will not be wrapped."],
          ["    This indent is preserved."]
long_desc "This line is appended to the description."

Parameters:

  • strs (Toys::WrappableString, String, Array<String>...)
  • file (String) (defaults to: nil)

    Optional. Read the description from the given file provided relative to the current toys file. The file must be a plain text file whose suffix is .txt.

  • data (String) (defaults to: nil)

    Optional. Read the description from the given data file. The file must be a plain text file whose suffix is .txt.

Returns:

  • (self)


614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/toys/dsl/tool.rb', line 614

def long_desc(*strs, file: nil, data: nil)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  if file
    unless source_info.source_path
      raise ::Toys::ToolDefinitionError,
            "Cannot set long_desc from a file because the tool is not defined in a file"
    end
    file = ::File.join(::File.dirname(source_info.source_path), file)
  elsif data
    file = source_info.find_data(data, type: :file)
  end
  strs += DSL::Internal.load_long_desc_file(file) if file
  cur_tool.append_long_desc(strs)
  self
end

#mixin(name, mixin_module = nil, &block) ⇒ self

Create a named mixin module that can be included by name from this tool or its subtools.

A mixin is a module that defines methods that can be called from a tool. It is commonly used to provide "utility" methods, implementing common functionality and allowing tools to share code.

Normally you provide a block and define the mixin's methods in that block. Alternatively, you can create a module separately and pass it directly to this directive.

Example

The following example creates a named mixin and uses it in a tool.

mixin "error-reporter" do
  def error message
    logger.error "An error occurred: #{message}"
    exit 1
  end
end

tool "build" do
  include "error-reporter"
  def run
    puts "Building..."
    error "Build failed!"
  end
end

Parameters:

  • name (String)

    Name of the mixin

  • mixin_module (Module) (defaults to: nil)

    Module to use as the mixin. Optional. Either pass a module here, or provide a block and define the mixin within the block.

  • block (Proc)

    Defines the mixin module.

Returns:

  • (self)


149
150
151
152
153
# File 'lib/toys/dsl/tool.rb', line 149

def mixin(name, mixin_module = nil, &block)
  cur_tool = DSL::Internal.current_tool(self, false)
  cur_tool&.add_mixin(name, mixin_module, &block)
  self
end

#on_interrupt(handler = nil, &block) ⇒ self

Specify how to handle interrupts.

You can provide either a block to be called, a Proc to be called, or the name of a method to be called. In each case, the block, Proc, or method can optionally take one argument, the Interrupt exception that was raised.

Note: this is equivalent to on_signal("SIGINT").

Example

tool "foo" do
  def run
    sleep 10
  end
  on_interrupt do
    puts "I was interrupted."
  end
end

Parameters:

  • handler (Proc, Symbol, nil) (defaults to: nil)

    The interrupt callback proc or method name. Pass nil to disable interrupt handling.

  • block (Proc)

    The interrupt callback as a block.

Returns:

  • (self)


1566
1567
1568
1569
1570
# File 'lib/toys/dsl/tool.rb', line 1566

def on_interrupt(handler = nil, &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.interrupt_handler = handler || block
  self
end

#on_signal(signal, handler = nil, &block) ⇒ self

Specify how to handle the given signal.

You can provide either a block to be called, a Proc to be called, or the name of a method to be called. In each case, the block, Proc, or method can optionally take one argument, the SignalException that was raised.

Example

tool "foo" do
  def run
    sleep 10
  end
  on_signal("QUIT") do |e|
    puts "Signal caught: #{e.signm}."
  end
end

Parameters:

  • signal (Integer, String, Symbol)

    The signal name or number

  • handler (Proc, Symbol, nil) (defaults to: nil)

    The signal callback proc or method name. Pass nil to disable signal handling.

  • block (Proc)

    The signal callback as a block.

Returns:

  • (self)


1597
1598
1599
1600
1601
# File 'lib/toys/dsl/tool.rb', line 1597

def on_signal(signal, handler = nil, &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.set_signal_handler(signal, handler || block)
  self
end

#on_usage_error(handler = nil, &block) ⇒ self

Specify how to handle usage errors.

You can provide either a block to be called, a Proc to be called, or the name of a method to be called. In each case, the block, Proc, or method can optionally take one argument, the array of usage errors reported.

Example

This tool runs even if a usage error is encountered, by setting the run method as the usage error handler.

tool "foo" do
  def run
    puts "Errors: #{usage_errors.join("\n")}"
  end
  on_usage_error :run
end

Parameters:

  • handler (Proc, Symbol, nil) (defaults to: nil)

    The interrupt callback proc or method name. Pass nil to disable interrupt handling.

  • block (Proc)

    The interrupt callback as a block.

Returns:

  • (self)


1628
1629
1630
1631
1632
# File 'lib/toys/dsl/tool.rb', line 1628

def on_usage_error(handler = nil, &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.usage_error_handler = handler || block
  self
end

#optional_arg(key, default: nil, accept: nil, complete: nil, display_name: nil, desc: nil, long_desc: nil, add_method: nil, &block) ⇒ self Also known as: optional

Add an optional positional argument to the current tool. You must specify a key which the script may use to obtain the argument value from the context. If an optional argument is not given on the command line, the value is set to the given default.

If the given key is a symbol representing a valid method name, then a helper method is automatically added to retrieve the value. Otherwise, if the key is a string or does not represent a valid method name, the tool can retrieve the value by calling Context#get.

Attributes of the arg may be passed in as arguments to this method, or set in a block passed to this method. If you provide a block, you can use directives in PositionalArg within the block.

Example

This tool creates a "link" to a given target. The link location is optional; if it is not given, it is inferred from the target.

tool "ln" do
  required_arg :target
  optional_arg :location
  def run
    loc = location || File.basename(target)
    puts "linking to #{target} from #{loc}..."
  end
end

Parameters:

  • key (String, Symbol)

    The key to use to retrieve the value from the execution context.

  • default (Object) (defaults to: nil)

    The default value. This is the value that will be set in the context if this argument is not provided on the command line. Defaults to nil.

  • accept (Object) (defaults to: nil)

    An acceptor that validates and/or converts the value. You may provide either the name of an acceptor you have defined, one of the default acceptors provided by OptionParser, or any other specification recognized by Acceptor.create. Optional. If not specified, accepts any value as a string.

  • complete (Object) (defaults to: nil)

    A specifier for shell tab completion for values of this arg. This is the empty completion by default. To customize completion, set this to the name of a previously defined completion, or any spec recognized by Completion.create.

  • display_name (String) (defaults to: nil)

    A name to use for display (in help text and error reports). Defaults to the key in upper case.

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the flag. See #desc for a description of the allowed formats. Defaults to the empty string.

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag. See #long_desc for a description of the allowed formats. (But note that this param takes an Array of description lines, rather than a series of arguments.) Defaults to the empty array.

  • add_method (true, false, nil) (defaults to: nil)

    Whether to add a method for this argument. If omitted or set to nil, uses the default behavior, which adds the method if the key is a symbol representing a legal method name that starts with a letter and does not override any public method in the Ruby Object class or collide with any method directly defined in the tool class.

  • block (Proc)

    Configures the positional argument. See PositionalArg for the directives that can be called in this block.

Returns:

  • (self)


1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
# File 'lib/toys/dsl/tool.rb', line 1187

def optional_arg(key,
                 default: nil, accept: nil, complete: nil, display_name: nil,
                 desc: nil, long_desc: nil, add_method: nil,
                 &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name,
                                   desc, long_desc, add_method)
  arg_dsl.instance_exec(arg_dsl, &block) if block
  arg_dsl._add_optional_to(cur_tool, key)
  DSL::Internal.maybe_add_getter(self, key, arg_dsl._get_add_method)
  self
end

#remaining_args(key, default: [], accept: nil, complete: nil, display_name: nil, desc: nil, long_desc: nil, add_method: nil, &block) ⇒ self Also known as: remaining

Specify what should be done with unmatched positional arguments. You must specify a key which the script may use to obtain the remaining args from the context.

If the given key is a symbol representing a valid method name, then a helper method is automatically added to retrieve the value. Otherwise, if the key is a string or does not represent a valid method name, the tool can retrieve the value by calling Context#get.

Attributes of the arg may be passed in as arguments to this method, or set in a block passed to this method. If you provide a block, you can use directives in PositionalArg within the block.

Example

This tool displays a "list" of the given directories. If no directories ar given, lists the current directory.

tool "ln" do
  remaining_args :directories
  def run
    dirs = directories.empty? ? [Dir.pwd] : directories
    dirs.each do |dir|
      puts "Listing directory #{dir}..."
    end
  end
end

Parameters:

  • key (String, Symbol)

    The key to use to retrieve the value from the execution context.

  • default (Object) (defaults to: [])

    The default value. This is the value that will be set in the context if no unmatched arguments are provided on the command line. Defaults to the empty array [].

  • accept (Object) (defaults to: nil)

    An acceptor that validates and/or converts the value. You may provide either the name of an acceptor you have defined, one of the default acceptors provided by OptionParser, or any other specification recognized by Acceptor.create. Optional. If not specified, accepts any value as a string.

  • complete (Object) (defaults to: nil)

    A specifier for shell tab completion for values of this arg. This is the empty completion by default. To customize completion, set this to the name of a previously defined completion, or any spec recognized by Completion.create.

  • display_name (String) (defaults to: nil)

    A name to use for display (in help text and error reports). Defaults to the key in upper case.

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the flag. See #desc for a description of the allowed formats. Defaults to the empty string.

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag. See #long_desc for a description of the allowed formats. (But note that this param takes an Array of description lines, rather than a series of arguments.) Defaults to the empty array.

  • add_method (true, false, nil) (defaults to: nil)

    Whether to add a method for these arguments. If omitted or set to nil, uses the default behavior, which adds the method if the key is a symbol representing a legal method name that starts with a letter and does not override any public method in the Ruby Object class or collide with any method directly defined in the tool class.

  • block (Proc)

    Configures the positional argument. See PositionalArg for the directives that can be called in this block.

Returns:

  • (self)


1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
# File 'lib/toys/dsl/tool.rb', line 1266

def remaining_args(key,
                   default: [], accept: nil, complete: nil, display_name: nil,
                   desc: nil, long_desc: nil, add_method: nil,
                   &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name,
                                   desc, long_desc, add_method)
  arg_dsl.instance_exec(arg_dsl, &block) if block
  arg_dsl._set_remaining_on(cur_tool, key)
  DSL::Internal.maybe_add_getter(self, key, arg_dsl._get_add_method)
  self
end

#require_exact_flag_match(state = true) ⇒ self

Require that flags must match exactly. That is, flags must appear in their entirety on the command line. (If false, substrings of flags are accepted as long as they are unambiguous.)

Issuing this directive by itself turns on exact match. You may turn it off by passsing false as the parameter.

Parameters:

  • state (Boolean) (defaults to: true)

Returns:

  • (self)


1388
1389
1390
1391
1392
# File 'lib/toys/dsl/tool.rb', line 1388

def require_exact_flag_match(state = true)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.require_exact_flag_match(state)
  self
end

#required_arg(key, accept: nil, complete: nil, display_name: nil, desc: nil, long_desc: nil, add_method: nil, &block) ⇒ self Also known as: required

Add a required positional argument to the current tool. You must specify a key which the script may use to obtain the argument value from the context.

If the given key is a symbol representing a valid method name, then a helper method is automatically added to retrieve the value. Otherwise, if the key is a string or does not represent a valid method name, the tool can retrieve the value by calling Context#get.

Attributes of the arg may be passed in as arguments to this method, or set in a block passed to this method. If you provide a block, you can use directives in PositionalArg within the block.

Example

This tool "moves" something from a source to destination, and takes two required arguments:

tool "mv" do
  required_arg :source
  required_arg :dest
  def run
    puts "moving from #{source} to #{dest}..."
  end
end

Parameters:

  • key (String, Symbol)

    The key to use to retrieve the value from the execution context.

  • accept (Object) (defaults to: nil)

    An acceptor that validates and/or converts the value. You may provide either the name of an acceptor you have defined, one of the default acceptors provided by OptionParser, or any other specification recognized by Acceptor.create. Optional. If not specified, accepts any value as a string.

  • complete (Object) (defaults to: nil)

    A specifier for shell tab completion for values of this arg. This is the empty completion by default. To customize completion, set this to the name of a previously defined completion, or any spec recognized by Completion.create.

  • display_name (String) (defaults to: nil)

    A name to use for display (in help text and error reports). Defaults to the key in upper case.

  • desc (String, Array<String>, Toys::WrappableString) (defaults to: nil)

    Short description for the flag. See #desc for a description of the allowed formats. Defaults to the empty string.

  • long_desc (Array<String,Array<String>,Toys::WrappableString>) (defaults to: nil)

    Long description for the flag. See #long_desc for a description of the allowed formats. (But note that this param takes an Array of description lines, rather than a series of arguments.) Defaults to the empty array.

  • add_method (true, false, nil) (defaults to: nil)

    Whether to add a method for this argument. If omitted or set to nil, uses the default behavior, which adds the method if the key is a symbol representing a legal method name that starts with a letter and does not override any public method in the Ruby Object class or collide with any method directly defined in the tool class.

  • block (Proc)

    Configures the positional argument. See PositionalArg for the directives that can be called in this block.

Returns:

  • (self)


1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
# File 'lib/toys/dsl/tool.rb', line 1108

def required_arg(key,
                 accept: nil, complete: nil, display_name: nil,
                 desc: nil, long_desc: nil, add_method: nil,
                 &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  arg_dsl = DSL::PositionalArg.new(accept, nil, complete, display_name,
                                   desc, long_desc, add_method)
  arg_dsl.instance_exec(arg_dsl, &block) if block
  arg_dsl._add_required_to(cur_tool, key)
  DSL::Internal.maybe_add_getter(self, key, arg_dsl._get_add_method)
  self
end

#set(key, value) ⇒ self #set(hash) ⇒ self

Set option values statically without creating helper methods.

Example

tool "hello" do
  set :greeting, "Hi there"
  def run
    puts "#{get(:greeting)}, world!"
  end
end

Overloads:

  • #set(key, value) ⇒ self

    Set a single value by key.

    Parameters:

    • key (String, Symbol)

      The key to use to retrieve the value from the execution context.

    • value (Object)

      The value to set.

    Returns:

    • (self)
  • #set(hash) ⇒ self

    Set multiple keys and values

    Parameters:

    • hash (Hash)

      The keys and values to set

    Returns:

    • (self)


1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
# File 'lib/toys/dsl/tool.rb', line 1349

def set(key, value = nil)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  if key.is_a?(::Hash)
    cur_tool.default_data.merge!(key)
  else
    cur_tool.default_data[key] = value
  end
  self
end

#set_context_directory(dir) ⇒ self

Set a custom context directory for this tool.

Parameters:

  • dir (String)

    Context directory

Returns:

  • (self)


1759
1760
1761
1762
1763
# File 'lib/toys/dsl/tool.rb', line 1759

def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
  cur_tool = DSL::Internal.current_tool(self, false)
  cur_tool&.custom_context_directory = dir
  self
end

#settingsToys::ToolDefinition::Settings

Get the settings for this tool.

Returns:



1826
1827
1828
# File 'lib/toys/dsl/tool.rb', line 1826

def settings
  DSL::Internal.current_tool(self, false)&.settings
end

#source_infoToys::SourceInfo

Return the current source info object.

Returns:



1693
1694
1695
# File 'lib/toys/dsl/tool.rb', line 1693

def source_info
  @__source.last
end

#static(key, value) ⇒ self #static(hash) ⇒ self

Set option values statically and create helper methods.

If any given key is a symbol representing a valid method name, then a helper method is automatically added to retrieve the value. Otherwise, if the key is a string or does not represent a valid method name, the tool can retrieve the value by calling Context#get.

Example

tool "hello" do
  static :greeting, "Hi there"
  def run
    puts "#{greeting}, world!"
  end
end

Overloads:

  • #static(key, value) ⇒ self

    Set a single value by key.

    Parameters:

    • key (String, Symbol)

      The key to use to retrieve the value from the execution context.

    • value (Object)

      The value to set.

    Returns:

    • (self)
  • #static(hash) ⇒ self

    Set multiple keys and values

    Parameters:

    • hash (Hash)

      The keys and values to set

    Returns:

    • (self)


1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
# File 'lib/toys/dsl/tool.rb', line 1310

def static(key, value = nil)
  cur_tool = DSL::Internal.current_tool(self, true)
  return self if cur_tool.nil?
  if key.is_a?(::Hash)
    cur_tool.default_data.merge!(key)
    key.each_key do |k|
      DSL::Internal.maybe_add_getter(self, k, true)
    end
  else
    cur_tool.default_data[key] = value
    DSL::Internal.maybe_add_getter(self, key, true)
  end
  self
end

#subtool_apply(&block) ⇒ Object

Applies the given block to all subtools, recursively. Effectively, the given block is run at the end of every tool block. This can be used, for example, to provide some shared configuration for all tools.

The block is applied only to subtools defined after the block appears. Subtools defined before the block appears are not affected.

Example

It is common for tools to use the :exec mixin to invoke external programs. This example automatically includes the exec mixin in all subtools, recursively, so you do not have to repeat the include directive in every tool.

# .toys.rb

subtool_apply do
  # Include the mixin only if the tool hasn't already done so
  unless include?(:exec)
    include :exec, exit_on_nonzero_status: true
  end
end

tool "foo" do
  def run
    # This tool has access to methods defined by the :exec mixin
    # because the above block is applied to the tool.
    sh "echo hello"
  end
end


1797
1798
1799
1800
1801
1802
# File 'lib/toys/dsl/tool.rb', line 1797

def subtool_apply(&block)
  cur_tool = DSL::Internal.current_tool(self, false)
  return self if cur_tool.nil?
  cur_tool.subtool_middleware_stack.add(:apply_config, parent_source: source_info, &block)
  self
end

#template(name, template_class = nil, &block) ⇒ self

Create a named template that can be expanded by name from this tool or its subtools.

A template is an object that generates DSL directives. You can use it to build "prefabricated" tools, and then instantiate them in your Toys files.

A template is an object that defines an expansion procedure. This procedure generates the DSL directives implemented by the template. The template object typically also includes attributes that are used to configure the expansion.

The simplest way to define a template is to pass a block to the #template directive. In the block, define an initialize method that accepts any arguments that may be passed to the template when it is instantiated and are used to configure the template. Define attr_readers or other methods to make this configuration accessible from the object. Then define an on_expand block that implements the template's expansion. The template object is passed as an object to the on_expand block.

Alternately, you can create a template class separately and pass it directly. See Template for details on creating a template class.

Example

The following example creates and uses a simple template. The template defines a tool, with a configurable name, that simply prints out a configurable message.

template "hello-generator" do
  def initialize(name, message)
    @name = name
    @message = message
  end
  attr_reader :name, :message
  on_expand do |template|
    tool template.name do
      to_run do
        puts template.message
      end
    end
  end
end

expand "hello-generator", "mytool", "mytool is running!"

Parameters:

  • name (String)

    Name of the template

  • template_class (Class) (defaults to: nil)

    Module to use as the mixin. Optional. Either pass a module here, or provide a block and define the mixin within the block.

  • block (Proc)

    Defines the template class.

Returns:

  • (self)


211
212
213
214
215
216
# File 'lib/toys/dsl/tool.rb', line 211

def template(name, template_class = nil, &block)
  cur_tool = DSL::Internal.current_tool(self, false)
  return self if cur_tool.nil?
  cur_tool.add_template(name, template_class, &block)
  self
end

#to_run(handler = nil, &block) ⇒ self Also known as: on_run

Specify how to run this tool.

Typically the entrypoint for a tool is a method named run. However, you can change this by passing a different method name, as a symbol, to #to_run.

You can also alternatively pass a block to #to_run. You might do this if your method needs access to local variables in the lexical scope. However, it is often more convenient to use #static to set those values in the context.

Examples

# Set a different method name as the entrypoint:

tool "foo" do
  to_run :foo
  def foo
    puts "The foo tool ran!"
  end
end

# Use a block to retain access to the enclosing lexical scope from
# the run method:

tool "foo" do
  cur_time = Time.now
  to_run do
    puts "The time at tool definition was #{cur_time}"
  end
end

# But the following is approximately equivalent:

tool "foo" do
  static :cur_time, Time.now
  def run
    puts "The time at tool definition was #{cur_time}"
  end
end

Parameters:

  • handler (Proc, Symbol, nil) (defaults to: nil)

    The run handler as a method name symbol or a proc, or nil to explicitly set as non-runnable.

  • block (Proc)

    The run handler as a block.

Returns:

  • (self)


1533
1534
1535
1536
1537
# File 'lib/toys/dsl/tool.rb', line 1533

def to_run(handler = nil, &block)
  cur_tool = DSL::Internal.current_tool(self, true)
  cur_tool&.run_handler = handler || block
  self
end

#tool(words, if_defined: :combine, delegate_to: nil, delegate_relative: nil, &block) ⇒ self

Create a subtool. You must provide a block defining the subtool.

Example

The following example defines a tool and two subtools within it.

tool "build" do
  tool "staging" do
    def run
      puts "Building staging"
    end
  end
  tool "production" do
    def run
      puts "Building production"
    end
  end
end

The following example uses delegate_to to define a tool that runs one of its subtools.

tool "test", delegate_to: ["test", "unit"] do
  tool "unit" do
    def run
      puts "Running unit tests"
    end
  end
end

Parameters:

  • words (String, Array<String>)

    The name of the subtool

  • if_defined (:combine, :reset, :ignore) (defaults to: :combine)

    What to do if a definition already exists for this tool. Possible values are :combine (the default) indicating the definition should be combined with the existing definition, :reset indicating the earlier definition should be reset and the new definition applied instead, or :ignore indicating the new definition should be ignored.

  • delegate_to (String, Array<String>) (defaults to: nil)

    Optional. This tool should delegate to another tool, specified by the full path. This path may be given as an array of strings, or a single string possibly delimited by path separators.

  • delegate_relative (String, Array<String>) (defaults to: nil)

    Optional. Similar to delegate_to, but takes a delegate name relative to the context in which this tool is being defined.

  • block (Proc)

    Defines the subtool.

Returns:

  • (self)


314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/toys/dsl/tool.rb', line 314

def tool(words, if_defined: :combine, delegate_to: nil, delegate_relative: nil, &block)
  subtool_words, next_remaining = DSL::Internal.analyze_name(self, words)
  subtool = @__loader.get_tool(subtool_words, @__priority)
  if subtool.includes_definition?
    case if_defined
    when :ignore
      return self
    when :reset
      subtool.reset_definition
    end
  end
  if delegate_to || delegate_relative
    delegate_to2 = @__words + @__loader.split_path(delegate_relative) if delegate_relative
    orig_block = block
    block = proc do
      self.delegate_to(delegate_to) if delegate_to
      self.delegate_to(delegate_to2) if delegate_to2
      instance_eval(&orig_block) if orig_block
    end
  end
  if block
    @__loader.load_block(source_info, block, subtool_words, next_remaining, @__priority)
  end
  self
end

#toys_version!(*requirements) ⇒ self

Asserts that the current Toys version against the given requirements, raising an exception if not.

Returns:

  • (self)

Raises:



1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
# File 'lib/toys/dsl/tool.rb', line 1852

def toys_version!(*requirements)
  require "rubygems"
  version = ::Gem::Version.new(Core::VERSION)
  requirement = ::Gem::Requirement.new(*requirements)
  unless requirement.satisfied_by?(version)
    raise Toys::ToolDefinitionError,
          "Toys version requirements #{requirement} not satisfied by #{version}"
  end
  self
end

#toys_version?(*requirements) ⇒ Boolean

Determines whether the current Toys version satisfies the given requirements.

Returns:

  • (Boolean)

    whether or not the requirements are satisfied



1836
1837
1838
1839
1840
1841
# File 'lib/toys/dsl/tool.rb', line 1836

def toys_version?(*requirements)
  require "rubygems"
  version = ::Gem::Version.new(Core::VERSION)
  requirement = ::Gem::Requirement.new(*requirements)
  requirement.satisfied_by?(version)
end

#truncate_load_path!Object

Remove lower-priority sources from the load path. This prevents lower- priority sources (such as Toys files from parent or global directories) from executing or defining tools.

This works only if no such sources have already loaded yet.

Raises:



1814
1815
1816
1817
1818
1819
# File 'lib/toys/dsl/tool.rb', line 1814

def truncate_load_path!
  unless @__loader.stop_loading_at_priority(@__priority)
    raise ToolDefinitionError,
          "Cannot truncate load path because tools have already been loaded"
  end
end