Class: Optplus::Parser
- Inherits:
-
Object
- Object
- Optplus::Parser
- Defined in:
- lib/optplus.rb
Overview
Optplus Parser
A wrapper class that adds a little value to writing scipts with optparse. Like Thor but without trying to do too much.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#program_name ⇒ Object
readonly
provides convenient access to the name of the program.
Class Method Summary collapse
-
.describe(action, description) ⇒ Object
Add a brief description for a specific action.
-
.description(*lines) ⇒ Object
Adds a description to the help/usage.
-
.help(action, *lines) ⇒ Object
add a block of helpful text for an action.
-
.nest_parser(name, klass, description) ⇒ Object
nest a parser for subcommands This will add the given name to the actions list and then parse the next argument as a subcommand The klass must inherit NestedParser.
-
.run! ⇒ Object
Do the option parsing and actioning stuff.
-
.usage(txt) ⇒ Object
define the usage banner, less “Usage: <prog_name>”!.
Instance Method Summary collapse
-
#all_arguments ⇒ Array
return all of the remaining args, or an empty array.
- #all_options ⇒ Object
-
#debug_option(opts, switch = '-D') ⇒ Object
add optparse option for debug mode.
-
#exit_on_error(msg = '') ⇒ Object
call this to exit the script in case of an error and ensure any tidying up has been done.
-
#get_option(key) ⇒ Object
get the value of the option.
-
#initialize ⇒ Parser
constructor
create an Optplus instance, define the options and parse the command line.
-
#man ⇒ Object
output all the help in one go!.
-
#next_argument ⇒ String
return the next argument, if there is one or nil otherwise.
-
#next_argument_or(default) ⇒ String
return the next argument or the given default.
-
#next_argument_or_error(msg) ⇒ String
return the next argument or raise exception with the given message.
-
#option?(key) ⇒ Boolean
check if the option has been set.
-
#set_option(key, value = true) ⇒ Object
set the value of the given option, which defaults to true.
-
#verbose_option(opts, switch = '-V') ⇒ Object
add optparse option for verbose mode.
Constructor Details
#initialize ⇒ Parser
create an Optplus instance, define the options and parse the command line
This method will call the following if they have been defined:
-
before_all - any setting up needed right at the start
-
options - to add options
-
before_actions - after options have been parsed but before actions are implemented
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 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/optplus.rb', line 200 def initialize @klass = self.class @klass._help ||= Hash.new @_help = false @_man = false @options = Hash.new self.before_all if self.respond_to?(:before_all) begin @_optparse = OptionParser.new do |opts| @program_name = opts.program_name opts. = "Usage: #{@program_name} #{@klass.}" opts.separator "" @klass._description.each do |dline| opts.separator " " + dline end opts.separator "" opts.separator "Actions:" opts.separator "" flags = 0 @klass._descriptions.each do |key, value| flag = @klass._help.has_key?(key.to_sym) ? '(-h)' : '' flags += 1 unless flag == '' opts.separator " #{key} - #{value} #{flag}" end if flags > 0 then opts.separator "" opts.separator " (-h indicates actions with additional help)" opts.separator "" end opts.separator "" opts.separator "Options:" opts.separator "" if @klass._help.length > 0 then help_string = 'use with an action for further help' else help_string = 'you are looking at it' end (opts) if self.respond_to?(:options) opts.on_tail('-h', '--help', help_string) do @_help = true end opts.on_tail('--man', 'output man-like help') do @_help = true @_man = true end end @_args = @_optparse.permute(ARGV) # trap a deliberate exit and force exit before # executing before_actions rescue ExitOnError => err puts err..red.bold unless err. == '' exit 1 end end |
Instance Attribute Details
#program_name ⇒ Object (readonly)
provides convenient access to the name of the program
270 271 272 |
# File 'lib/optplus.rb', line 270 def program_name @program_name end |
Class Method Details
.describe(action, description) ⇒ Object
Add a brief description for a specific action
Add a little Thor-like description before each method. Unlike Thor, you will not get told off if there is no corresponding method but its probably a good idea if you add one.
56 57 58 59 60 61 |
# File 'lib/optplus.rb', line 56 def describe(action, description) @_actions ||= Array.new @_actions << action.to_s @_descriptions ||= Hash.new @_descriptions[action] = description end |
.description(*lines) ⇒ Object
Adds a description to the help/usage
This takes any number of string arguments and displays them as separate lines.
43 44 45 |
# File 'lib/optplus.rb', line 43 def description(*lines) @_description = lines end |
.help(action, *lines) ⇒ Object
add a block of helpful text for an action
Adds all of the arguments as lines to display when you use the help switch with the given argument, instead of the general help. Note that optplus does not allow options specific to actions so this is just text.
73 74 75 76 |
# File 'lib/optplus.rb', line 73 def help(action, *lines) @_help ||= Hash.new @_help[action] = lines end |
.nest_parser(name, klass, description) ⇒ Object
nest a parser for subcommands This will add the given name to the actions list and then parse the next argument as a subcommand The klass must inherit NestedParser
178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/optplus.rb', line 178 instance_eval do def nest_parser(name, klass, description) self.describe(name, description) self._help[name] = klass class_eval %Q{ def #{name} #{klass}.run!(self) end } end end |
.run! ⇒ Object
Do the option parsing and actioning stuff
If you write an optplus class, run the script and nothing happens it is because you forgot to add MyClass.run! Simple and easily done.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/optplus.rb', line 97 def run! @_parent ||= nil @_help ||= Hash.new begin me = self.new if me._needs_help? then me._help_me elsif me._args.length > 0 then action = me.next_argument alup = @_actions.abbrev(action) if alup.has_key?(action) then me.before_actions if me.respond_to?(:before_actions) begin me.send(alup[action].to_sym) # trap a deliberate exit and tidy up # if required rescue Optplus::ExitOnError => err puts err..red.bold unless err. == '' me.after_actions if me.respond_to?(:after_actions) raise Optplus::ExitOnError, '' # with no message end me.after_actions if me.respond_to?(:after_actions) else puts "Sorry, What?" puts "" me._get_help end else me._get_help end return true rescue OptionParser::InvalidOption => opterr puts "Error: Invalid Option".red.bold puts "I do not understand the option: #{opterr.args.join}" rescue OptionParser::InvalidArgument => opterr puts "Error: You have entered an invalid argument to an option".red.bold puts "The option in question is: #{opterr.args.join(' ')}" rescue OptionParser::AmbiguousOption => opterr puts "Error: You need to be clearer than that".red.bold puts "I am not be sure what option you mean: #{opterr.args.join}" rescue OptionParser::AmbiguousArgument => opterr puts "Error: You need to be clearer than that".red.bold puts "I am not sure what argument you mean: #{opterr.args.join(' ')}" rescue OptionParser::MissingArgument => opterr puts "Error: You need to provide an argument with that option".red.bold puts "This is the option in question: #{opterr.args.join}" rescue OptionParser::ParseError => opterr puts "Error: the command line is not as expected".red.bold puts opterr.to_s rescue Optplus::ParseError => err puts "Error: #{err.}".red.bold rescue Optplus::ExitOnError => err puts err..red.bold unless err. == '' raise Optplus::ExitOnError, '' unless @_parent.nil? end # only rescued exceptions will reach here exit 1 if @_parent.nil? end |
.usage(txt) ⇒ Object
define the usage banner, less “Usage: <prog_name>”!
For example: usage “[options] [actions] [filename]” becomes: “Usage: progname [options] [actions] [filename]”
34 35 36 |
# File 'lib/optplus.rb', line 34 def usage(txt) @_banner = txt end |
Instance Method Details
#all_arguments ⇒ Array
return all of the remaining args, or an empty array
This clears all remaining arguments so that subsequent calls e.g. to #next_argument return nil
330 331 332 333 334 |
# File 'lib/optplus.rb', line 330 def all_arguments args = @_args.dup @_args = Array.new return args end |
#all_options ⇒ Object
371 372 373 |
# File 'lib/optplus.rb', line 371 def @options.dup end |
#debug_option(opts, switch = '-D') ⇒ Object
add optparse option for debug mode
276 277 278 279 280 |
# File 'lib/optplus.rb', line 276 def debug_option(opts, switch='-D') opts.on_tail(switch, '--debug', 'show debug information') do |d| @options[:debug] = d end end |
#exit_on_error(msg = '') ⇒ Object
call this to exit the script in case of an error and ensure any tidying up has been done
385 386 387 |
# File 'lib/optplus.rb', line 385 def exit_on_error(msg='') raise Optplus::ExitOnError, msg end |
#get_option(key) ⇒ Object
get the value of the option
Returns nil if there is no option with the given key
367 368 369 |
# File 'lib/optplus.rb', line 367 def get_option(key) @options[key] end |
#man ⇒ Object
output all the help in one go!
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/optplus.rb', line 433 def man puts "Help Manual for #{@program_name}" puts "" _get_help @klass._help.each_pair do |action, help| puts "Action: #{action}" puts "" if help.kind_of?(Array) then help.each do |hline| puts " " + hline end else np = help.new(self) np._get_help(2) puts "" help._help.each_pair do |subaction, subhelp| puts " Subaction: #{subaction}" puts "" subhelp.each do |hline| puts " " + hline end puts "" end end puts " " end puts "" end |
#next_argument ⇒ String
return the next argument, if there is one or nil otherwise
300 301 302 |
# File 'lib/optplus.rb', line 300 def next_argument @_args.shift end |
#next_argument_or(default) ⇒ String
return the next argument or the given default
308 309 310 |
# File 'lib/optplus.rb', line 308 def next_argument_or(default) next_argument || default end |
#next_argument_or_error(msg) ⇒ String
return the next argument or raise exception with the given message
The exception does not need to be handled because run! will rescue it and display an error message.
320 321 322 |
# File 'lib/optplus.rb', line 320 def next_argument_or_error(msg) next_argument || raise(Optplus::ParseError, msg) end |
#option?(key) ⇒ Boolean
check if the option has been set
379 380 381 |
# File 'lib/optplus.rb', line 379 def option?(key) @options.has_key?(key) end |
#set_option(key, value = true) ⇒ Object
set the value of the given option, which defaults to true
If a value is omitted then the option is set to be true
357 358 359 |
# File 'lib/optplus.rb', line 357 def set_option(key, value=true) @options[key] = value end |
#verbose_option(opts, switch = '-V') ⇒ Object
add optparse option for verbose mode
286 287 288 289 290 |
# File 'lib/optplus.rb', line 286 def verbose_option(opts, switch='-V') opts.on_tail(switch, '--verbose', 'show verbose information') do |v| @options[:verbose] = v end end |