module Toys::DSL::Tool
def self.current_tool(tool_class, activate)
def self.current_tool(tool_class, activate) memoize_var = activate ? :@__active_tool : :@__cur_tool if tool_class.instance_variable_defined?(memoize_var) tool_class.instance_variable_get(memoize_var) else loader = tool_class.instance_variable_get(:@__loader) words = tool_class.instance_variable_get(:@__words) priority = tool_class.instance_variable_get(:@__priority) cur_tool = if activate loader.activate_tool(words, priority) else loader.get_tool(words, priority) end if cur_tool && activate source = tool_class.instance_variable_get(:@__source).last cur_tool.lock_source(source) end tool_class.instance_variable_set(memoize_var, cur_tool) end end
def self.load_long_desc_file(path)
def self.load_long_desc_file(path) if ::File.extname(path) == ".txt" begin ::File.readlines(path).map do |line| line = line.chomp line =~ /^\s/ ? [line] : line end rescue ::SystemCallError => e raise Toys::ToolDefinitionError, e.to_s end else raise Toys::ToolDefinitionError, "Cannot load long desc from file type: #{path}" end end
def self.maybe_add_getter(tool_class, key)
def self.maybe_add_getter(tool_class, key) if key.is_a?(::Symbol) && key.to_s =~ /^[_a-zA-Z]\w*[!\?]?$/ && key != :run unless tool_class.public_method_defined?(key) tool_class.class_eval do define_method(key) do self[key] end end end end end
def self.new_class(words, priority, loader)
def self.new_class(words, priority, loader) tool_class = ::Class.new(::Toys::Context) tool_class.extend(DSL::Tool) tool_class.instance_variable_set(:@__words, words) tool_class.instance_variable_set(:@__priority, priority) tool_class.instance_variable_set(:@__loader, loader) tool_class.instance_variable_set(:@__remaining_words, nil) tool_class.instance_variable_set(:@__source, []) tool_class end
def self.prepare(tool_class, remaining_words, source)
def self.prepare(tool_class, remaining_words, source) tool_class.instance_variable_set(:@__remaining_words, remaining_words) tool_class.instance_variable_get(:@__source).push(source) yield ensure tool_class.instance_variable_get(:@__source).pop end
def self.resolve_mixin(mod, cur_tool, loader)
def self.resolve_mixin(mod, cur_tool, loader) name = mod.to_s if mod.is_a?(::String) mod = cur_tool.lookup_mixin(mod) elsif mod.is_a?(::Symbol) mod = loader.resolve_standard_mixin(name) end unless mod.is_a?(::Module) raise ToolDefinitionError, "Module not found: #{name.inspect}" end mod end
def acceptor(name, spec = nil, type_desc: nil, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- See the description for recognized forms.
- 
        type_desc(String) -- Type description string, shown in help.
- 
        spec(Object) -- See the description for recognized values.
- 
        name(String) -- The acceptor name.
def acceptor(name, spec = nil, type_desc: nil, &block) cur_tool = DSL::Tool.current_tool(self, false) cur_tool&.add_acceptor(name, spec, type_desc: type_desc || name.to_s, &block) self end
def alias_tool(word, target)
- 
        (self)-
Parameters:
- 
        target(String, Array) -- Relative path to the target of the
- 
        word(String) -- The name of the alias
def alias_tool(word, target) tool(word, delegate_to: @__words + @__loader.split_path(target)) self end
def all_required(desc: nil, long_desc: nil, name: nil, report_collisions: true,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Adds flags to the group. See {Toys::DSL::FlagGroup}
- 
        prepend(Boolean) -- If `true`, prepend rather than append the
- 
        report_collisions(Boolean) -- If `true`, raise an exception if a
- 
        name(String, Symbol, nil) -- The name of the group, or nil for no
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
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
def at_least_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Adds flags to the group. See {Toys::DSL::FlagGroup}
- 
        prepend(Boolean) -- If `true`, prepend rather than append the
- 
        report_collisions(Boolean) -- If `true`, raise an exception if a
- 
        name(String, Symbol, nil) -- The name of the group, or nil for no
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
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
def at_most_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Adds flags to the group. See {Toys::DSL::FlagGroup}
- 
        prepend(Boolean) -- If `true`, prepend rather than append the
- 
        report_collisions(Boolean) -- If `true`, raise an exception if a
- 
        name(String, Symbol, nil) -- The name of the group, or nil for no
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
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
def complete_tool_args(spec = nil, **options, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) --
- 
        options(Hash) --
- 
        spec(Object) --
def complete_tool_args(spec = nil, **options, &block) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? cur_tool.completion = Completion.scalarize_spec(spec, options, block) self end
def completion(name, spec = nil, **options, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- See the description for recognized forms.
- 
        options(Hash) -- Additional options to pass to the completion.
- 
        spec(Object) -- See the description for recognized values.
- 
        name(String) -- Name of the completion
def completion(name, spec = nil, **options, &block) cur_tool = DSL::Tool.current_tool(self, false) return self if cur_tool.nil? cur_tool.add_completion(name, spec, **options, &block) self end
def context_directory
- 
        (nil)- if there is no context.
- 
        (String)- Context directory path
def context_directory DSL::Tool.current_tool(self, false)&.context_directory || source_info.context_directory end
def current_tool
- 
        (Toys::Tool)-
def current_tool DSL::Tool.current_tool(self, false) end
def delegate_to(target)
- 
        (self)-
Parameters:
- 
        target(String, Array) -- The full path to the delegate
def delegate_to(target) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? cur_tool.delegate_to(@__loader.split_path(target)) self end
def desc(str)
- 
        (self)-
Parameters:
- 
        str(Toys::WrappableString, String, Array) --
def desc(str) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? cur_tool.desc = str self end
def disable_argument_parsing
- 
        (self)-
def disable_argument_parsing DSL::Tool.current_tool(self, true)&.disable_argument_parsing self end
def disable_flag(*flags)
- 
        (self)-
Parameters:
- 
        flags(String...) -- The flags to disable
def disable_flag(*flags) DSL::Tool.current_tool(self, true)&.disable_flag(*flags) self end
def enforce_flags_before_args(state = true)
- 
        (self)-
Parameters:
- 
        state(Boolean) --
def enforce_flags_before_args(state = true) DSL::Tool.current_tool(self, true)&.enforce_flags_before_args(state) self end
def exactly_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Adds flags to the group. See {Toys::DSL::FlagGroup}
- 
        prepend(Boolean) -- If `true`, prepend rather than append the
- 
        report_collisions(Boolean) -- If `true`, raise an exception if a
- 
        name(String, Symbol, nil) -- The name of the group, or nil for no
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
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
def expand(template_class, *args, **kwargs)
- 
        (self)-
Parameters:
- 
        args(Object...) -- Template arguments
- 
        template_class(Class, String, Symbol) -- The template, either as a
def expand(template_class, *args, **kwargs) cur_tool = DSL::Tool.current_tool(self, false) return self if cur_tool.nil? name = template_class.to_s if template_class.is_a?(::String) template_class = cur_tool.lookup_template(template_class) elsif template_class.is_a?(::Symbol) template_class = @__loader.resolve_standard_template(name) end if template_class.nil? raise ToolDefinitionError, "Template not found: #{name.inspect}" end template = Compat.instantiate(template_class, args, kwargs, nil) yield template if block_given? class_exec(template, &template_class.expansion) self end
def find_data(path, type: nil)
- 
        (nil)- if the given data path is not found.
- 
        (String)- Absolute path of the data.
Parameters:
- 
        type(nil, :file, :directory) -- Type of file system object to find.
- 
        path(String) -- The path to find
def find_data(path, type: nil) source_info.find_data(path, type: type) end
def flag(key, *flags,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Configures the flag. See {Toys::DSL::Flag} for the
- 
        display_name(String) -- A display name for this flag, used in help
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
- 
        group(Toys::FlagGroup, String, Symbol, nil) -- Group for this flag.
- 
        report_collisions(Boolean) -- Raise an exception if a flag is
- 
        complete_values(Object) -- A specifier for shell tab completion
- 
        complete_flags(Object) -- A specifier for shell tab completion
- 
        handler(Proc, nil, :set, :push) -- An optional handler for
- 
        default(Object) -- The default value. This is the value that will
- 
        accept(Object) -- An acceptor that validates and/or converts the
- 
        flags(String...) -- The flags in OptionParser format.
- 
        key(String, Symbol) -- The key to use to retrieve the value from
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, &block) cur_tool = DSL::Tool.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 ) flag_dsl.instance_exec(flag_dsl, &block) if block flag_dsl._add_to(cur_tool, key) DSL::Tool.maybe_add_getter(self, key) self end
def flag_group(type: :optional, desc: nil, long_desc: nil, name: nil,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Adds flags to the group. See {Toys::DSL::FlagGroup}
- 
        prepend(Boolean) -- If `true`, prepend rather than append the
- 
        report_collisions(Boolean) -- If `true`, raise an exception if a
- 
        name(String, Symbol, nil) -- The name of the group, or nil for no
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
- 
        type(Symbol) -- The type of group. Allowed values: `:required`,
def flag_group(type: :optional, desc: nil, long_desc: nil, name: nil, report_collisions: true, prepend: false, &block) cur_tool = DSL::Tool.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
def include(mod, *args, **kwargs)
- 
        (self)-
Parameters:
- 
        kwargs(keywords) -- Keyword arguments to pass to the initializer
- 
        args(Object...) -- Arguments to pass to the initializer
- 
        mod(Module, Symbol, String) -- Module or module name.
def include(mod, *args, **kwargs) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? mod = DSL::Tool.resolve_mixin(mod, cur_tool, @__loader) if included_modules.include?(mod) raise ToolDefinitionError, "Mixin already included: #{mod.name}" end cur_tool.mark_includes_modules super(mod) if mod.respond_to?(:initializer) callback = mod.initializer cur_tool.add_initializer(callback, *args, **kwargs) if callback end if mod.respond_to?(:inclusion) callback = mod.inclusion class_exec(*args, **kwargs, &callback) if callback end self end
def include?(mod)
- 
        (nil)- if the current tool is not active.
- 
        (Boolean)- Whether the mixin is included
Parameters:
- 
        mod(Module, Symbol, String) -- Module or module name.
def include?(mod) cur_tool = DSL::Tool.current_tool(self, false) return if cur_tool.nil? super(DSL::Tool.resolve_mixin(mod, cur_tool, @__loader)) end
def load(path)
- 
        (self)-
Parameters:
- 
        path(String) -- The file or directory to load.
def load(path) @__loader.load_path(source_info, path, @__words, @__remaining_words, @__priority) self end
def long_desc(*strs, file: nil, data: nil)
- 
        (self)-
Parameters:
- 
        data(String) -- Optional. Read the description from the given data
- 
        file(String) -- Optional. Read the description from the given file
- 
        strs(Toys::WrappableString, String, Array) --... 
def long_desc(*strs, file: nil, data: nil) cur_tool = DSL::Tool.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::Tool.load_long_desc_file(file) if file cur_tool.append_long_desc(strs) self end
def method_added(_meth)
def method_added(_meth) DSL::Tool.current_tool(self, true)&.check_definition_state(is_method: true) end
def mixin(name, mixin_module = nil, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- Defines the mixin module.
- 
        mixin_module(Module) -- Module to use as the mixin. Optional.
- 
        name(String) -- Name of the mixin
def mixin(name, mixin_module = nil, &block) cur_tool = DSL::Tool.current_tool(self, false) cur_tool&.add_mixin(name, mixin_module, &block) self end
def on_interrupt(handler = nil, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- The interrupt callback as a block.
- 
        handler(Proc, Symbol, nil) -- The interrupt callback proc or method
def on_interrupt(handler = nil, &block) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? cur_tool.interrupt_handler = handler || block self end
def on_usage_error(handler = nil, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- The interrupt callback as a block.
- 
        handler(Proc, Symbol, nil) -- The interrupt callback proc or method
def on_usage_error(handler = nil, &block) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? cur_tool.usage_error_handler = handler || block self end
def optional_arg(key,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Configures the positional argument. See
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
- 
        display_name(String) -- A name to use for display (in help text and
- 
        complete(Object) -- A specifier for shell tab completion for
- 
        accept(Object) -- An acceptor that validates and/or converts the
- 
        default(Object) -- The default value. This is the value that will
- 
        key(String, Symbol) -- The key to use to retrieve the value from
def optional_arg(key, default: nil, accept: nil, complete: nil, display_name: nil, desc: nil, long_desc: nil, &block) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name, desc, long_desc) arg_dsl.instance_exec(arg_dsl, &block) if block arg_dsl._add_optional_to(cur_tool, key) DSL::Tool.maybe_add_getter(self, key) self end
def remaining_args(key,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Configures the positional argument. See
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
- 
        display_name(String) -- A name to use for display (in help text and
- 
        complete(Object) -- A specifier for shell tab completion for
- 
        accept(Object) -- An acceptor that validates and/or converts the
- 
        default(Object) -- The default value. This is the value that will
- 
        key(String, Symbol) -- The key to use to retrieve the value from
def remaining_args(key, default: [], accept: nil, complete: nil, display_name: nil, desc: nil, long_desc: nil, &block) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name, desc, long_desc) arg_dsl.instance_exec(arg_dsl, &block) if block arg_dsl._set_remaining_on(cur_tool, key) DSL::Tool.maybe_add_getter(self, key) self end
def require_exact_flag_match(state = true)
- 
        (self)-
Parameters:
- 
        state(Boolean) --
def require_exact_flag_match(state = true) DSL::Tool.current_tool(self, true)&.require_exact_flag_match(state) self end
def required_arg(key,
- 
        (self)-
Parameters:
- 
        block(Proc) -- Configures the positional argument. See
- 
        long_desc(Array) --,Toys::WrappableString> 
- 
        desc(String, Array) -- Short, Toys::WrappableString 
- 
        display_name(String) -- A name to use for display (in help text and
- 
        complete(Object) -- A specifier for shell tab completion for
- 
        accept(Object) -- An acceptor that validates and/or converts the
- 
        key(String, Symbol) -- The key to use to retrieve the value from
def required_arg(key, accept: nil, complete: nil, display_name: nil, desc: nil, long_desc: nil, &block) cur_tool = DSL::Tool.current_tool(self, true) return self if cur_tool.nil? arg_dsl = DSL::PositionalArg.new(accept, nil, complete, display_name, desc, long_desc) arg_dsl.instance_exec(arg_dsl, &block) if block arg_dsl._add_required_to(cur_tool, key) DSL::Tool.maybe_add_getter(self, key) self end
def set(key, value = nil)
- 
        (self)-
- 
        (self)-
Parameters:
- 
        hash(Hash) -- The keys and values to set
- 
        value(Object) -- The value to set.
- 
        key(String, Symbol) -- The key to use to retrieve the value from
Overloads:
- 
        set(hash)
- 
        set(key, value)
def set(key, value = nil) cur_tool = DSL::Tool.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
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
- 
        (self)-
Parameters:
- 
        dir(String) -- Context directory
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName cur_tool = DSL::Tool.current_tool(self, false) return self if cur_tool.nil? cur_tool.custom_context_directory = dir self end
def source_info
- 
        (Toys::SourceInfo)- Source info.
def source_info @__source.last end
def static(key, value = nil)
- 
        (self)-
- 
        (self)-
Parameters:
- 
        hash(Hash) -- The keys and values to set
- 
        value(Object) -- The value to set.
- 
        key(String, Symbol) -- The key to use to retrieve the value from
Overloads:
- 
        static(hash)
- 
        static(key, value)
def static(key, value = nil) cur_tool = DSL::Tool.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::Tool.maybe_add_getter(self, k) end else cur_tool.default_data[key] = value DSL::Tool.maybe_add_getter(self, key) end self end
def subtool_apply(&block)
end
end
sh "echo hello"
# because the above block is applied to the tool.
# This tool has access to methods defined by the :exec mixin
def run
tool "foo" do
end
end
include :exec, exit_on_nonzero_status: true
unless include?(:exec)
# Include the mixin only if the tool hasn't already done so
subtool_apply do
# .toys.rb
directive in every tool.
subtools, recursively, so you do not have to repeat the `include`
programs. This example automatically includes the exec mixin in all
It is common for tools to use the `:exec` mixin to invoke external
## Example
appears. Subtools defined before the block appears are not affected.
The block is applied only to subtools defined *after* the block
for example, to provide some shared configuration for all tools.
given block is run at the *end* of every tool block. This can be used,
Applies the given block to all subtools, recursively. Effectively, the
#
def subtool_apply(&block) cur_tool = DSL::Tool.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
def template(name, template_class = nil, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- Defines the template class.
- 
        template_class(Class) -- Module to use as the mixin. Optional.
- 
        name(String) -- Name of the template
def template(name, template_class = nil, &block) cur_tool = DSL::Tool.current_tool(self, false) return self if cur_tool.nil? cur_tool.add_template(name, template_class, &block) self end
def to_run(&block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- The run method.
def to_run(&block) define_method(:run, &block) self end
def tool(words, if_defined: :combine, delegate_to: nil, &block)
- 
        (self)-
Parameters:
- 
        block(Proc) -- Defines the subtool.
- 
        delegate_to(String, Array) -- Optional. This tool should
- 
        if_defined(:combine, :reset, :ignore) -- What to do if a definition
- 
        words(String, Array) -- The name of the subtool
def tool(words, if_defined: :combine, delegate_to: nil, &block) subtool_words = @__words.dup next_remaining = @__remaining_words @__loader.split_path(words).each do |word| word = word.to_s subtool_words << word next_remaining = Loader.next_remaining_words(next_remaining, word) end subtool = @__loader.get_tool(subtool_words, @__priority) if subtool.includes_definition? case if_defined when :ignore return self when :reset subtool.reset_definition(@__loader) end end if delegate_to delegator = proc { self.delegate_to(delegate_to) } @__loader.load_block(source_info, delegator, subtool_words, next_remaining, @__priority) end if block @__loader.load_block(source_info, block, subtool_words, next_remaining, @__priority) end self end
def toys_version!(*requirements)
- 
        (Toys::ToolDefinitionError)- if the current Toys version does not
Returns:
- 
        (self)-
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
def toys_version?(*requirements)
- 
        (Boolean)- whether or not the requirements are satisfied
def toys_version?(*requirements) require "rubygems" version = ::Gem::Version.new(Core::VERSION) requirement = ::Gem::Requirement.new(*requirements) requirement.satisfied_by?(version) end