Class: Dispatcher
- Inherits:
-
Object
- Object
- Dispatcher
- Defined in:
- lib/cli-dispatcher.rb
Overview
Constructs a program that can operate a number of user-provided commands. To use this class, subclass it and define methods of the form:
def cmd_name(args...)
Then create an instance of the class and call one of the dispatch methods, typically:
[DispatcherSubclass].new.dispatch_argv
To provide help and/or a category for a command, define the methods
def help_name; [string] end
def cat_name; [string] end
For the help command, the first line should be a short description of the command, which will be used in a summary table describing the command. For the category, all commands with the same category will be grouped together in the help summary display.
This class incorporates optparse, providing the commands setup_options and add_options to pass through options specifications.
Class Method Summary collapse
-
.add_structured_commands ⇒ Object
Adds commands relevant when this dispatcher uses Structured data inputs.
Instance Method Summary collapse
-
#add_options(opts) ⇒ Object
Adds command-line options for this class.
- #cmd_explain(class_name) ⇒ Object
- #cmd_help(cmd = nil, all: true) ⇒ Object
-
#cmd_interactive ⇒ Object
Runs the dispatcher in interactive mode, in which command lines are read from a prompt.
- #cmd_template(class_name) ⇒ Object
-
#dispatch(cmd, *args) ⇒ Object
Dispatches a single command with given arguments.
-
#dispatch_argv(default_interactive = false) ⇒ Object
Reads ARGV and dispatches a command.
- #help_cmds(cmds) ⇒ Object
- #help_explain ⇒ Object
- #help_help ⇒ Object
- #help_interactive ⇒ Object
- #help_string(cmd, all: true) ⇒ Object
- #help_template ⇒ Object
-
#interactive_prompt ⇒ Object
Returns the string for the interactive prompt.
-
#setup_options ⇒ Object
Creates an OptionParser object for this Dispatcher.
- #signature_string(cmd) ⇒ Object
Class Method Details
.add_structured_commands ⇒ Object
Adds commands relevant when this dispatcher uses Structured data inputs.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/cli-dispatcher.rb', line 197 def self.add_structured_commands def help_explain return " Displays an explanation of a Structured class.\n\n Use this to assist in generating or checking a Rubric file.\n EOF\n end\n\n def cmd_explain(class_name)\n c = Object.const_get(class_name)\n unless c.is_a?(Class) && c.include?(Structured)\n raise \"Invalid class \#{class_name}\"\n end\n c.explain\n end\n\n def help_template\n return <<~EOF\n Produces a template for the given Structured class.\n EOF\n end\n\n def cmd_template(class_name)\n c = Object.const_get(class_name)\n unless c.is_a?(Class) && c.include?(Structured)\n raise(\"Invalid class \#{class_name}\")\n end\n puts c.template\n end\nend\n" |
Instance Method Details
#add_options(opts) ⇒ Object
Adds command-line options for this class. By default, this method does nothing. Subclasses may override this method to add options. The method will be automatically invoked during a dispatch_argv call, thereby constructing an OptionParser object to handle the command-line arguments.
The argument to this method is an OptionParser object, to which the desired options may be added. The banner and -h/–help options will be added automatically to the OptionParser object.
257 258 |
# File 'lib/cli-dispatcher.rb', line 257 def (opts) end |
#cmd_explain(class_name) ⇒ Object
206 207 208 209 210 211 212 |
# File 'lib/cli-dispatcher.rb', line 206 def cmd_explain(class_name) c = Object.const_get(class_name) unless c.is_a?(Class) && c.include?(Structured) raise "Invalid class #{class_name}" end c.explain end |
#cmd_help(cmd = nil, all: true) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/cli-dispatcher.rb', line 121 def cmd_help(cmd = nil, all: true) if cmd warn("") warn(help_string(cmd)) warn("") exit(1) end warn("Run 'help [command]' for further help on that command.") warn("") grouped_methods = methods.map { |m| s = m.to_s s.start_with?("cmd_") ? s.delete_prefix("cmd_") : nil }.compact.group_by { |m| cat_m = "cat_#{m}".to_sym respond_to?(cat_m) ? send(cat_m) : nil } help_cmds(grouped_methods.delete(nil)) if grouped_methods.include?(nil) grouped_methods.sort.each do |cat, cmds| warn("\n#{cat}\n\n") help_cmds(cmds) end end |
#cmd_interactive ⇒ Object
Runs the dispatcher in interactive mode, in which command lines are read from a prompt.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/cli-dispatcher.rb', line 166 def cmd_interactive stty_save = `stty -g`.chomp loop do begin buf = Reline.readline(interactive_prompt, true) exit unless buf args = buf.shellsplit next if args.empty? exit if args.first == 'exit' dispatch(*args) rescue Interrupt system("stty", stty_save) exit rescue STDERR.puts $!. end end end |
#cmd_template(class_name) ⇒ Object
220 221 222 223 224 225 226 |
# File 'lib/cli-dispatcher.rb', line 220 def cmd_template(class_name) c = Object.const_get(class_name) unless c.is_a?(Class) && c.include?(Structured) raise("Invalid class #{class_name}") end puts c.template end |
#dispatch(cmd, *args) ⇒ Object
Dispatches a single command with given arguments. If the command is not found, then issues a help warning. Returns true or false depending on whether the command executed successfully.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/cli-dispatcher.rb', line 68 def dispatch(cmd, *args) cmd_sym = "cmd_#{cmd}".to_sym begin if respond_to?(cmd_sym) send(cmd_sym, *args) return true else warn("Unknown command #{cmd_sym}. Run 'help' for a list of commands.") return false end rescue ArgumentError if $!.backtrace_locations.first.base_label == cmd_sym.to_s warn("#{cmd}: wrong number of arguments.") warn("Usage: #{signature_string(cmd)}") else raise end return false end end |
#dispatch_argv(default_interactive = false) ⇒ Object
Reads ARGV and dispatches a command. If no arguments are given, an appropriate warning is issued and the program terminates.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/cli-dispatcher.rb', line 36 def dispatch_argv(default_interactive = false) @option_parser ||= OptionParser.new (@option_parser) @option_parser. = " Usage: \#{File.basename($0)} [options] command [arguments...]\n Run '\#{File.basename($0)} help' for a list of commands.\n\n Options:\n EOF\n @option_parser.on_tail('-h', '--help', 'Show this help') do\n warn(@option_parser)\n warn(\"\\nCommands:\")\n cmd_help\n exit 1\n end\n\n @option_parser.parse!\n if !ARGV.empty?\n exit dispatch(*ARGV) ? 0 : 1\n elsif default_interactive\n cmd_interactive\n else\n STDERR.puts(@option_parser)\n exit 1\n end\nend\n" |
#help_cmds(cmds) ⇒ Object
148 149 150 151 152 153 154 155 156 |
# File 'lib/cli-dispatcher.rb', line 148 def help_cmds(cmds) cmds.sort.each do |cmd| warn(TextTools.line_break( help_string(cmd, all: false), prefix: " " * 12, first_prefix: cmd.ljust(11) + ' ', )) end end |
#help_explain ⇒ Object
198 199 200 201 202 203 204 |
# File 'lib/cli-dispatcher.rb', line 198 def help_explain return " Displays an explanation of a Structured class.\n\n Use this to assist in generating or checking a Rubric file.\n EOF\nend\n" |
#help_help ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/cli-dispatcher.rb', line 113 def help_help return " Displays help on commands.\n\n Run 'help [command]' for further help on that command.\n EOF\nend\n" |
#help_interactive ⇒ Object
158 159 160 |
# File 'lib/cli-dispatcher.rb', line 158 def help_interactive return "Start an interactive shell for entering commands." end |
#help_string(cmd, all: true) ⇒ Object
89 90 91 92 93 94 95 96 97 |
# File 'lib/cli-dispatcher.rb', line 89 def help_string(cmd, all: true) cmd_sym = "help_#{cmd}".to_sym return signature_string(cmd) unless respond_to?(cmd_sym) if all return $0 + " " + signature_string(cmd) + "\n\n" + send(cmd_sym) else return send(cmd_sym).to_s.split("\n", 2).first end end |
#help_template ⇒ Object
214 215 216 217 218 |
# File 'lib/cli-dispatcher.rb', line 214 def help_template return " Produces a template for the given Structured class.\n EOF\nend\n" |
#interactive_prompt ⇒ Object
Returns the string for the interactive prompt. Subclasses can override this method to offer more detailed prompts.
189 190 191 |
# File 'lib/cli-dispatcher.rb', line 189 def interactive_prompt return "#{File.basename($0)}> " end |
#setup_options ⇒ Object
Creates an OptionParser object for this Dispatcher. The options for the OptionParser are defined in a block passed to this method. The block receives one argument, which is the OptionParser object being created.
The banner and -h/–help options will be added automatically to the created OptionParser object.
For a slightly simpler way to set up options for this Dispatcher object, see the add_options method.
241 242 243 244 245 |
# File 'lib/cli-dispatcher.rb', line 241 def @option_parser = OptionParser.new do |opts| yield(opts) end end |
#signature_string(cmd) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/cli-dispatcher.rb', line 99 def signature_string(cmd) cmd_sym = "cmd_#{cmd}".to_sym raise "No such command" unless respond_to?(cmd_sym) return cmd + " " + method(cmd_sym).parameters.map { |type, name| case type when :req then name.to_s when :opt then "[#{name}]" when :rest then "*#{name}" when :keyreq, :key, :keyrest, :block then nil else raise "Unknown parameter type #{type}" end }.compact.join(" ") end |