Module: Commandable
- Included in:
- AppController
- Defined in:
- lib/commandable/version.rb,
lib/commandable/coloring.rb,
lib/commandable/help_text.rb,
lib/commandable/controller.rb,
lib/commandable/exceptions.rb,
lib/commandable/app_controller.rb,
lib/commandable/command_parser.rb,
lib/commandable/argument_parser.rb,
lib/commandable/execution_controller.rb
Overview
Extending your class with this module allows you to use the #command method above your method. This makes them executable from the command line.
Defined Under Namespace
Modules: VERSION Classes: AccessorError, AppController, ConfigurationError, ExclusiveMethodClashError, MissingRequiredCommandError, MissingRequiredParameterError, SyntaxError, UnknownCommandError
Constant Summary collapse
- HELP_COMMAND =
Default command that always gets added to end of the command list
{:help => {:description => "you're looking at it now", :argument_list => "", :class=>"Commandable", :class_method=>true}}
Class Attribute Summary collapse
-
.app_exe ⇒ Object
Used when building the usage line, e.g.
-
.app_info ⇒ Object
Describes your application, printed at the top of help/usage messages.
-
.clear_screen ⇒ Object
If the screen should be cleared before printing help.
-
.clear_screen_code ⇒ Object
What escape code will be used to clear the screen.
-
.color_app_exe ⇒ Object
What color the app_exe will be in the usage line in the help message.
-
.color_app_info ⇒ Object
What color the app_info text will be in the help message.
-
.color_command ⇒ Object
What color the word “command” and the commands themselves will be in the help message.
-
.color_description ⇒ Object
What color the description column header and text will be in the help message.
-
.color_error_description ⇒ Object
What color the error description will be in error messages.
-
.color_error_name ⇒ Object
What color the friendly name of the error will be in error messages.
-
.color_error_word ⇒ Object
What color the word “Error:” text will be in error messages.
-
.color_output ⇒ Object
If the output will be colorized or not.
-
.color_parameter ⇒ Object
What color the word “parameter” and the parameters themselves will be in the help message.
-
.color_usage ⇒ Object
What color the word “Usage:” will be in the help message.
-
.verbose_parameters ⇒ Object
If optional parameters show default values, true by default.
Class Method Summary collapse
-
.[](index) ⇒ Object
Access the command array using the method name (symbol or string).
-
.class_cache ⇒ Object
A hash of instances created when calling instance methods It’s keyed using the class name: “ClassName”=>#<ClassName:0x00000100b1f188>.
-
.clear_commands ⇒ Object
Clears all methods from the list of available commands This is mostly useful for testing.
-
.commands ⇒ Object
An array of methods that can be executed from the command line.
-
.each(&block) ⇒ Object
Convenience method to iterate over the array of commands using the Commandable module.
-
.execute(argv = ARGV.clone, silent = false) ⇒ Object
A wrapper for the execution_queue that runs the queue and traps errors.
-
.execution_queue(argv) ⇒ Object
Returns an array of executable procs based on the given array of commands and parameters Normally this would come from the command line parameters in the ARGV array.
-
.help(additional_info = nil) ⇒ Object
Generates an array of the available commands with a list of their parameters and the method’s description.
-
.reset_all ⇒ Object
Resets the class to default values clearing any commands and setting the colors back to their default values.
-
.reset_colors ⇒ Object
Resets colors to their default values and disables color output.
-
.reset_screen_clearing ⇒ Object
Resets the escape code used for screen clearing and disables screen clearing.
Instance Method Summary collapse
-
#parse_arguments(parameters) ⇒ Object
Parse a method’s parameters building the argument list for printing help/usage.
-
#parse_optional(method_def, argument) ⇒ Object
Parses a method defition for the optional values of given argument.
-
#readline(file, line_number) ⇒ Object
Reads a line from a source code file.
Class Attribute Details
.app_exe ⇒ Object
Used when building the usage line, e.g. Usage: app_exe [command] [parameters]
12 13 14 |
# File 'lib/commandable/help_text.rb', line 12 def app_exe @app_exe end |
.app_info ⇒ Object
Describes your application, printed at the top of help/usage messages
9 10 11 |
# File 'lib/commandable/help_text.rb', line 9 def app_info @app_info end |
.clear_screen ⇒ Object
If the screen should be cleared before printing help
31 32 33 |
# File 'lib/commandable/coloring.rb', line 31 def clear_screen @clear_screen end |
.clear_screen_code ⇒ Object
What escape code will be used to clear the screen
34 35 36 |
# File 'lib/commandable/coloring.rb', line 34 def clear_screen_code @clear_screen_code end |
.color_app_exe ⇒ Object
What color the app_exe will be in the usage line in the help message
13 14 15 |
# File 'lib/commandable/coloring.rb', line 13 def color_app_exe @color_app_exe end |
.color_app_info ⇒ Object
What color the app_info text will be in the help message
11 12 13 |
# File 'lib/commandable/coloring.rb', line 11 def color_app_info @color_app_info end |
.color_command ⇒ Object
What color the word “command” and the commands themselves will be in the help message
15 16 17 |
# File 'lib/commandable/coloring.rb', line 15 def color_command @color_command end |
.color_description ⇒ Object
What color the description column header and text will be in the help message
17 18 19 |
# File 'lib/commandable/coloring.rb', line 17 def color_description @color_description end |
.color_error_description ⇒ Object
What color the error description will be in error messages
28 29 30 |
# File 'lib/commandable/coloring.rb', line 28 def color_error_description @color_error_description end |
.color_error_name ⇒ Object
What color the friendly name of the error will be in error messages
26 27 28 |
# File 'lib/commandable/coloring.rb', line 26 def color_error_name @color_error_name end |
.color_error_word ⇒ Object
What color the word “Error:” text will be in error messages
24 25 26 |
# File 'lib/commandable/coloring.rb', line 24 def color_error_word @color_error_word end |
.color_output ⇒ Object
If the output will be colorized or not
8 9 10 |
# File 'lib/commandable/coloring.rb', line 8 def color_output @color_output end |
.color_parameter ⇒ Object
What color the word “parameter” and the parameters themselves will be in the help message
19 20 21 |
# File 'lib/commandable/coloring.rb', line 19 def color_parameter @color_parameter end |
.color_usage ⇒ Object
What color the word “Usage:” will be in the help message
21 22 23 |
# File 'lib/commandable/coloring.rb', line 21 def color_usage @color_usage end |
.verbose_parameters ⇒ Object
If optional parameters show default values, true by default
15 16 17 |
# File 'lib/commandable/help_text.rb', line 15 def verbose_parameters @verbose_parameters end |
Class Method Details
.[](index) ⇒ Object
Access the command array using the method name (symbol or string)
19 20 21 22 |
# File 'lib/commandable/command_parser.rb', line 19 def [](index) raise AccessorError unless index.is_a? String or index.is_a? Symbol @@commands[index.to_sym] end |
.class_cache ⇒ Object
A hash of instances created when calling instance methods It’s keyed using the class name: “ClassName”=>#<ClassName:0x00000100b1f188>
14 15 16 |
# File 'lib/commandable/command_parser.rb', line 14 def class_cache @@class_cache end |
.clear_commands ⇒ Object
Clears all methods from the list of available commands This is mostly useful for testing.
26 27 28 29 |
# File 'lib/commandable/command_parser.rb', line 26 def clear_commands @@command_options = nil @@commands = HELP_COMMAND.dup end |
.commands ⇒ Object
An array of methods that can be executed from the command line
8 9 10 |
# File 'lib/commandable/command_parser.rb', line 8 def commands @@commands.dup end |
.each(&block) ⇒ Object
Convenience method to iterate over the array of commands using the Commandable module
32 33 34 35 36 |
# File 'lib/commandable/command_parser.rb', line 32 def each(&block) @@commands.each do |key, value| yield key => value end end |
.execute(argv = ARGV.clone, silent = false) ⇒ Object
A wrapper for the execution_queue that runs the queue and traps errors. If an error occurs inside this method it will print out a complete list of availavle methods with usage instructions and exit gracefully.
If you do not want the output from your methods to be printed out automatically run the execute command with silent set to anything other than false or nil.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/commandable/execution_controller.rb', line 16 def execute(argv=ARGV.clone, silent=false) begin command_queue = execution_queue(argv) command_queue.each do |com| return_value = com[:proc].call puts return_value if !silent || com[:method] == :help end rescue SystemExit => kernel_exit Kernel.exit kernel_exit.status rescue Exception => exception if exception.respond_to?(:friendly_name) set_colors puts help("\n #{@c_error_word}Error:#{@c_reset} #{@c_error_name}#{exception.friendly_name}#{@c_reset}\n #{@c_error_description}#{exception.}#{@c_reset}\n\n") else puts exception.inspect puts exception.backtrace.collect{|line| " #{line}"} end end end |
.execution_queue(argv) ⇒ Object
Returns an array of executable procs based on the given array of commands and parameters Normally this would come from the command line parameters in the ARGV array.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/commandable/execution_controller.rb', line 38 def execution_queue(argv) arguments = argv.dup method_hash = {} last_method = nil if arguments.empty? arguments << @@default_method.keys[0] if @@default_method and !@@default_method.values[0][:parameters].flatten.include?(:req) end arguments << "help" if arguments.empty? # Parse the command line into methods and their parameters arguments.each do |arg| if Commandable[arg] last_method = arg.to_sym method_hash.merge!(last_method=>[]) else unless last_method default = find_by_subkey(:default) # Raise an error if there is no default method and the first item isn't a method raise UnknownCommandError, arguments.first if default.empty? # Raise an error if there is a default method but it doesn't take any parameters raise UnknownCommandError, (arguments.first) if default.values[0][:argument_list] == "" last_method = default.keys.first method_hash.merge!(last_method=>[]) end method_hash[last_method] << arg end # Test for missing required switches @@commands.select do |key, value| if value[:required] and method_hash[key].nil? # If the required switch is also a default have the error be a missing parameter instead of a missing command if value[:default] method_hash.merge!(key=>[]) else raise MissingRequiredCommandError, key end end end end # Build an array of procs to be called for each method and its given parameters proc_array = [] method_hash.each do |meth, params| command = @@commands[meth] if command[:parameters] && !command[:parameters].empty? #Change the method name for attr_writers meth = "#{meth}=" if command[:parameters][0][0] == :writer # Get a list of required parameters and make sure all of them were provided required = command[:parameters].select{|param| [:req, :writer].include?(param[0])} required.shift(params.count) raise MissingRequiredParameterError, {:method=>meth, :parameters=>required.collect!{|meth| meth[1]}.to_s[1...-1].gsub(":",""), :default=>command[:default]} unless required.empty? end # Test for duplicate XORs proc_array.select{|x| x[:xor] and x[:xor]==command[:xor] }.each {|bad| raise ExclusiveMethodClashError, "#{meth}, #{bad[:method]}"} klass = Object command[:class].split(/::/).each { |name| klass = klass.const_get(name) } ## Look for class in class cache unless command[:class_method] klass = (@@class_cache[klass.name] ||= klass.new) end proc_array << {:method=>meth, :xor=>command[:xor], :parameters=>params, :priority=>command[:priority], :proc=>lambda{klass.send(meth, *params)}} end proc_array.sort{|a,b| a[:priority] <=> b[:priority]}.reverse end |
.help(additional_info = nil) ⇒ Object
Generates an array of the available commands with a list of their parameters and the method’s description. This includes the applicaiton info and app name if given. It’s meant to be printed to the command line.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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 62 63 64 65 66 67 68 |
# File 'lib/commandable/help_text.rb', line 21 def help(additional_info=nil) set_colors set_screen_clear cmd_length = "Command".length parm_length = "Parameters".length max_command = [(@@commands.keys.max_by{|key| key.to_s.length }).to_s.length, cmd_length].max max_parameter = @@commands[@@commands.keys.max_by{|key| @@commands[key][:argument_list].length }][:argument_list].length max_parameter = [parm_length, max_parameter].max if max_parameter > 0 usage_text = " #{@c_usage}Usage:#{@c_reset} " if Commandable.app_exe cmd_text = "<#{@c_command + @c_bold}command#{@c_reset}>" parm_text = " [#{@c_parameter + @c_bold}parameters#{@c_reset}]" if max_parameter > 0 usage_text += "#{@c_app_exe + app_exe + @c_reset} #{cmd_text}#{parm_text} [#{cmd_text}#{parm_text}...]" end array = [usage_text, ""] array.unshift additional_info if additional_info array.unshift (@c_app_info + Commandable.app_info + @c_reset) if Commandable.app_info array.unshift @s_clear_screen_code header_text = " #{" "*(max_command-cmd_length)}#{@c_command + @c_bold}Command#{@c_reset} " header_text += "#{@c_parameter + @c_bold}Parameters #{@c_reset}#{" "*(max_parameter-parm_length)}" if max_parameter > 0 header_text += "#{@c_description + @c_bold}Description#{@c_reset}" array << header_text array += @@commands.keys.collect do |key| is_default = (@@default_method and key == @@default_method.keys[0]) default_color = is_default ? @c_bold : "" help_line = " #{" "*(max_command-key.length)}#{@c_command + default_color + key.to_s + @c_reset}"+ " #{default_color + @c_parameter + @@commands[key][:argument_list] + @c_reset}" help_line += "#{" "*(max_parameter-@@commands[key][:argument_list].length)} " if max_parameter > 0 # indent new lines description = @@commands[key][:description].gsub("\n", "\n" + (" "*(max_command + max_parameter + (max_parameter > 0 ? 1 : 0) + 4))) help_line += ": #{default_color + @c_description}#{"<#{@@commands[key][:xor]}> " if @@commands[key][:xor]}" + "#{description}" + "#{" (default)" if is_default}#{@c_reset}" end array << nil end |
.reset_all ⇒ Object
Resets the class to default values clearing any commands and setting the colors back to their default values.
7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/commandable/controller.rb', line 7 def reset_all clear_commands reset_colors reset_screen_clearing @app_info = nil @app_exe = nil @verbose_parameters = true @@default_method = nil @@class_cache = {} end |
.reset_colors ⇒ Object
Resets colors to their default values and disables color output
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/commandable/coloring.rb', line 37 def reset_colors @color_output = false #Term::ANSIColor.coloring = true c = Term::ANSIColor @color_app_info = c.intense_white + c.bold @color_app_exe = c.intense_green + c.bold @color_command = c.intense_yellow @color_description = c.intense_white @color_parameter = c.intense_cyan @color_usage = c.intense_black + c.bold @color_error_word = c.intense_black + c.bold @color_error_name = c.intense_red + c.bold @color_error_description = c.intense_white + c.bold @color_bold = c.bold @color_reset = c.reset end |
.reset_screen_clearing ⇒ Object
Resets the escape code used for screen clearing and disables screen clearing.
58 59 60 61 |
# File 'lib/commandable/coloring.rb', line 58 def reset_screen_clearing @clear_screen = false @clear_screen_code = "\e[H\e[2J" end |
Instance Method Details
#parse_arguments(parameters) ⇒ Object
Parse a method’s parameters building the argument list for printing help/usage
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/commandable/argument_parser.rb', line 4 def parse_arguments(parameters) parameter_string = "" method_definition = nil parameters.each do |parameter| arg_type = parameter[0] arg = parameter[1] case arg_type when :req parameter_string += " #{arg}" when :opt if Commandable.verbose_parameters # figure out what the default value is method_definition ||= readline(@@method_file, @@method_line) default = parse_optional(method_definition, arg) parameter_string += " [#{arg}=#{default}]" else parameter_string += " [#{arg}]" end when :rest parameter_string += " *#{arg}" when :block parameter_string += " &#{arg}" end end parameter_string.strip end |
#parse_optional(method_def, argument) ⇒ Object
Parses a method defition for the optional values of given argument.
41 42 43 |
# File 'lib/commandable/argument_parser.rb', line 41 def parse_optional(method_def, argument) method_def.scan(/#{argument}\s*=\s*("[^"\r\n]*"|'[^'\r\n]*'|[0-9]*)/)[0][0] end |
#readline(file, line_number) ⇒ Object
Reads a line from a source code file.
32 33 34 35 36 37 38 |
# File 'lib/commandable/argument_parser.rb', line 32 def readline(file, line_number) current_line = 0 File.open(file).each do |line_text| current_line += 1 return line_text.strip if current_line == line_number end end |