diff options
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib')
6 files changed, 556 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary.rb b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary.rb new file mode 100644 index 0000000..cd38f78 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require File.expand_path("mercenary/version", __dir__) +require "optparse" +require "logger" + +module Mercenary + autoload :Command, File.expand_path("mercenary/command", __dir__) + autoload :Option, File.expand_path("mercenary/option", __dir__) + autoload :Presenter, File.expand_path("mercenary/presenter", __dir__) + autoload :Program, File.expand_path("mercenary/program", __dir__) + + # Public: Instantiate a new program and execute. + # + # name - the name of your program + # + # Returns nothing. + def self.program(name) + program = Program.new(name) + yield program + program.go(ARGV) + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/command.rb b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/command.rb new file mode 100644 index 0000000..08ddf94 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/command.rb @@ -0,0 +1,281 @@ +# frozen_string_literal: false + +module Mercenary + class Command + attr_reader :name + attr_reader :description + attr_reader :syntax + attr_accessor :options + attr_accessor :commands + attr_accessor :actions + attr_reader :map + attr_accessor :parent + attr_reader :trace + attr_reader :aliases + + # Public: Creates a new Command + # + # name - the name of the command + # parent - (optional) the instancce of Mercenary::Command which you wish to + # be the parent of this command + # + # Returns nothing + def initialize(name, parent = nil) + @name = name + @options = [] + @commands = {} + @actions = [] + @map = {} + @parent = parent + @trace = false + @aliases = [] + end + + # Public: Sets or gets the command version + # + # version - the command version (optional) + # + # Returns the version and sets it if an argument is non-nil + def version(version = nil) + @version = version if version + @version + end + + # Public: Sets or gets the syntax string + # + # syntax - the string which describes this command's usage syntax (optional) + # + # Returns the syntax string and sets it if an argument is present + def syntax(syntax = nil) + @syntax = syntax if syntax + syntax_list = [] + syntax_list << parent.syntax.to_s.gsub(%r!<[\w\s-]+>!, "").gsub(%r!\[[\w\s-]+\]!, "").strip if parent + syntax_list << (@syntax || name.to_s) + syntax_list.join(" ") + end + + # Public: Sets or gets the command description + # + # description - the description of what the command does (optional) + # + # Returns the description and sets it if an argument is present + def description(desc = nil) + @description = desc if desc + @description + end + + # Public: Sets the default command + # + # command_name - the command name to be executed in the event no args are + # present + # + # Returns the default command if there is one, `nil` otherwise + def default_command(command_name = nil) + if command_name + if commands.key?(command_name) + @default_command = commands[command_name] if command_name + @default_command + else + raise ArgumentError, "'#{command_name}' couldn't be found in this command's list of commands." + end + else + @default_command + end + end + + # Public: Adds an option switch + # + # sym - the variable key which is used to identify the value of the switch + # at runtime in the options hash + # + # Returns nothing + def option(sym, *options) + new_option = Option.new(sym, options) + @options << new_option + @map[new_option] = sym + end + + # Public: Adds a subcommand + # + # cmd_name - the name of the command + # block - a block accepting the new instance of Mercenary::Command to be + # modified (optional) + # + # Returns nothing + def command(cmd_name) + cmd = Command.new(cmd_name, self) + yield cmd + @commands[cmd_name] = cmd + end + + # Public: Add an alias for this command's name to be attached to the parent + # + # cmd_name - the name of the alias + # + # Returns nothing + def alias(cmd_name) + logger.debug "adding alias to parent for self: '#{cmd_name}'" + aliases << cmd_name + @parent.commands[cmd_name] = self + end + + # Public: Add an action Proc to be executed at runtime + # + # block - the Proc to be executed at runtime + # + # Returns nothing + def action(&block) + @actions << block + end + + # Public: Fetch a Logger (stdlib) + # + # level - the logger level (a Logger constant, see docs for more info) + # + # Returns the instance of Logger + + def logger(level = nil) + unless @logger + @logger = Logger.new(STDOUT) + @logger.level = level || Logger::INFO + @logger.formatter = proc do |severity, _datetime, _progname, msg| + "#{identity} | " << "#{severity.downcase.capitalize}:".ljust(7) << " #{msg}\n" + end + end + + @logger.level = level unless level.nil? + @logger + end + + # Public: Run the command + # + # argv - an array of string args + # opts - the instance of OptionParser + # config - the output config hash + # + # Returns the command to be executed + def go(argv, opts, config) + opts.banner = "Usage: #{syntax}" + process_options(opts, config) + add_default_options(opts) + + if argv[0] && cmd = commands[argv[0].to_sym] + logger.debug "Found subcommand '#{cmd.name}'" + argv.shift + cmd.go(argv, opts, config) + else + logger.debug "No additional command found, time to exec" + self + end + end + + # Public: Add this command's options to OptionParser and set a default + # action of setting the value of the option to the inputted hash + # + # opts - instance of OptionParser + # config - the Hash in which the option values should be placed + # + # Returns nothing + def process_options(opts, config) + options.each do |option| + opts.on(*option.for_option_parser) do |x| + config[map[option]] = x + end + end + end + + # Public: Add version and help options to the command + # + # opts - instance of OptionParser + # + # Returns nothing + def add_default_options(opts) + option "show_help", "-h", "--help", "Show this message" + option "show_version", "-v", "--version", "Print the name and version" + option "show_backtrace", "-t", "--trace", "Show the full backtrace when an error occurs" + opts.on("-v", "--version", "Print the version") do + puts "#{name} #{version}" + exit(0) + end + + opts.on("-t", "--trace", "Show full backtrace if an error occurs") do + @trace = true + end + + opts.on_tail("-h", "--help", "Show this message") do + puts self + exit + end + end + + # Public: Execute all actions given the inputted args and options + # + # argv - (optional) command-line args (sans opts) + # config - (optional) the Hash configuration of string key to value + # + # Returns nothing + def execute(argv = [], config = {}) + if actions.empty? && !default_command.nil? + default_command.execute + else + actions.each { |a| a.call(argv, config) } + end + end + + # Public: Check if this command has a subcommand + # + # sub_command - the name of the subcommand + # + # Returns true if this command is the parent of a command of name + # 'sub_command' and false otherwise + def has_command?(sub_command) + commands.key?(sub_command) + end + + # Public: Identify this command + # + # Returns a string which identifies this command + def ident + "<Command name=#{identity}>" + end + + # Public: Get the full identity (name & version) of this command + # + # Returns a string containing the name and version if it exists + def identity + "#{full_name} #{version}".strip + end + + # Public: Get the name of the current command plus that of + # its parent commands + # + # Returns the full name of the command + def full_name + the_name = [] + the_name << parent.full_name if parent&.full_name + the_name << name + the_name.join(" ") + end + + # Public: Return all the names and aliases for this command. + # + # Returns a comma-separated String list of the name followed by its aliases + def names_and_aliases + ([name.to_s] + aliases).compact.join(", ") + end + + # Public: Build a string containing a summary of the command + # + # Returns a one-line summary of the command. + def summarize + " #{names_and_aliases.ljust(20)} #{description}" + end + + # Public: Build a string containing the command name, options and any subcommands + # + # Returns the string identifying this command, its options and its subcommands + def to_s + Presenter.new(self).print_command + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/option.rb b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/option.rb new file mode 100644 index 0000000..dfd21d5 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/option.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +module Mercenary + class Option + attr_reader :config_key, :description, :short, :long, :return_type + + # Public: Create a new Option + # + # config_key - the key in the config hash to which the value of this option + # will map + # info - an array containing first the switches, then an optional + # return type (e.g. Array), then a description of the option + # + # Returns nothing + def initialize(config_key, info) + @config_key = config_key + while arg = info.shift + begin + @return_type = Object.const_get(arg.to_s) + next + rescue NameError + end + if arg.start_with?("-") + if arg.start_with?("--") + @long = arg + else + @short = arg + end + next + end + @description = arg + end + end + + # Public: Fetch the array containing the info OptionParser is interested in + # + # Returns the array which OptionParser#on wants + def for_option_parser + [short, long, return_type, description].flatten.reject { |o| o.to_s.empty? } + end + + # Public: Build a string representation of this option including the + # switches and description + # + # Returns a string representation of this option + def to_s + "#{formatted_switches} #{description}" + end + + # Public: Build a beautifully-formatted string representation of the switches + # + # Returns a formatted string representation of the switches + def formatted_switches + [ + switches.first.rjust(10), + switches.last.ljust(13), + ].join(", ").gsub(%r! , !, " ").gsub(%r!, !, " ") + end + + # Public: Hash based on the hash value of instance variables + # + # Returns a Fixnum which is unique to this Option based on the instance variables + def hash + instance_variables.map do |var| + instance_variable_get(var).hash + end.reduce(:^) + end + + # Public: Check equivalence of two Options based on equivalence of their + # instance variables + # + # Returns true if all the instance variables are equal, false otherwise + def eql?(other) + return false unless self.class.eql?(other.class) + + instance_variables.map do |var| + instance_variable_get(var).eql?(other.instance_variable_get(var)) + end.all? + end + + # Public: Fetch an array of switches, including the short and long versions + # + # Returns an array of two strings. An empty string represents no switch in + # that position. + def switches + [short, long].map(&:to_s) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/presenter.rb b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/presenter.rb new file mode 100644 index 0000000..11685fe --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/presenter.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +module Mercenary + class Presenter + attr_accessor :command + + # Public: Make a new Presenter + # + # command - a Mercenary::Command to present + # + # Returns nothing + def initialize(command) + @command = command + end + + # Public: Builds a string representation of the command usage + # + # Returns the string representation of the command usage + def usage_presentation + " #{command.syntax}" + end + + # Public: Builds a string representation of the options + # + # Returns the string representation of the options + def options_presentation + return nil unless command_options_presentation || parent_command_options_presentation + + [command_options_presentation, parent_command_options_presentation].compact.join("\n") + end + + def command_options_presentation + return nil if command.options.empty? + + options = command.options + options -= command.parent.options if command.parent + options.map(&:to_s).join("\n") + end + + # Public: Builds a string representation of the options for parent + # commands + # + # Returns the string representation of the options for parent commands + def parent_command_options_presentation + return nil unless command.parent + + Presenter.new(command.parent).options_presentation + end + + # Public: Builds a string representation of the subcommands + # + # Returns the string representation of the subcommands + def subcommands_presentation + return nil if command.commands.empty? + + command.commands.values.uniq.map(&:summarize).join("\n") + end + + # Public: Builds the command header, including the command identity and description + # + # Returns the command header as a String + def command_header + header = command.identity.to_s + header << " -- #{command.description}" if command.description + header + end + + # Public: Builds a string representation of the whole command + # + # Returns the string representation of the whole command + def command_presentation + msg = [] + msg << command_header + msg << "Usage:" + msg << usage_presentation + + if opts = options_presentation + msg << "Options:\n#{opts}" + end + if subcommands = subcommands_presentation + msg << "Subcommands:\n#{subcommands_presentation}" + end + msg.join("\n\n") + end + + # Public: Turn a print_* into a *_presentation or freak out + # + # meth - the method being called + # args - an array of arguments passed to the missing method + # block - the block passed to the missing method + # + # Returns the value of whatever function is called + def method_missing(meth, *args, &block) + if meth.to_s =~ %r!^print_(.+)$! + send("#{Regexp.last_match(1).downcase}_presentation") + else + # You *must* call super if you don't handle the method, + # otherwise you'll mess up Ruby's method lookup. + super + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/program.rb b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/program.rb new file mode 100644 index 0000000..a8d0c52 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/program.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Mercenary + class Program < Command + attr_reader :optparse + attr_reader :config + + # Public: Creates a new Program + # + # name - the name of the program + # + # Returns nothing + def initialize(name) + @config = {} + super(name) + end + + # Public: Run the program + # + # argv - an array of string args (usually ARGV) + # + # Returns nothing + def go(argv) + logger.debug("Using args passed in: #{argv.inspect}") + + cmd = nil + + @optparse = OptionParser.new do |opts| + cmd = super(argv, opts, @config) + end + + begin + @optparse.parse!(argv) + rescue OptionParser::InvalidOption => e + logger.error "Whoops, we can't understand your command." + logger.error e.message.to_s + logger.error "Run your command again with the --help switch to see available options." + abort + end + + logger.debug("Parsed config: #{@config.inspect}") + + begin + cmd.execute(argv, @config) + rescue StandardError => e + if cmd.trace + raise e + else + logger.error e.message + abort + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/version.rb b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/version.rb new file mode 100644 index 0000000..3f3e475 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/mercenary-0.4.0/lib/mercenary/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Mercenary + VERSION = "0.4.0" +end |
