class Morpheus::Cli::CliRegistry
Public Class Methods
add(klass, command_name=nil)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 201 def add(klass, command_name=nil) klass_command_name = cli_ize(klass.name.split('::')[-1]) if has_command?(klass_command_name) instance.remove(klass_command_name) end command_name ||= klass_command_name instance.add(command_name, klass) end
all()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 226 def all instance.all end
all_aliases()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 230 def all_aliases instance.all_aliases end
cached_command_list()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 292 def cached_command_list @cached_command_list ||= (all.keys + all_aliases.keys).collect { |it| it.to_s }.sort end
clear_cached_command_list()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 296 def clear_cached_command_list @cached_command_list = nil end
cli_ize(klass_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 234 def cli_ize(klass_name) # borrowed from ActiveSupport return klass_name unless klass_name =~ /[A-Z-]|::/ word = klass_name.to_s.gsub(/::/, '/') word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(?=\b|[^a-z])/) { "#{$1 && '_'}" } word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2') word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') word.tr!("-", "_") word.downcase! word.chop.tr('_', '-') end
exec(command_name, args)
click to toggle source
todo: move execution out of the CliRegistry
# File lib/morpheus/cli/cli_registry.rb, line 75 def exec(command_name, args) exec_command(command_name, args) end
exec_alias(alias_name, args)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 111 def exec_alias(alias_name, args) found_alias_command = instance.get_alias(alias_name) if !found_alias_command raise Morpheus::Cli::CommandError.new("'#{alias_name}' is not a defined alias.") end # if !is_valid_expression(found_alias_command) # raise Morpheus::Cli::CommandError.new("alias '#{alias_name}' is not a valid expression: #{found_alias_command}") # end input = found_alias_command if args && !args.empty? input = "#{found_alias_command} " + args.collect {|arg| arg.include?(" ") ? "\"#{arg}\"" : "#{arg}" }.join(" ") end exec_expression(input) end
exec_command(command_name, args)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 79 def exec_command(command_name, args) #puts "exec_command(#{command_name}, #{args})" result = nil if has_alias?(command_name) result = exec_alias(command_name, args) elsif has_command?(command_name) begin result = instance.get(command_name).new.handle(args) rescue SystemExit => e result = Morpheus::Cli::ErrorHandler.new(Morpheus::Terminal.instance.stderr).handle_error(e) # lol rescue => e result = Morpheus::Cli::ErrorHandler.new(Morpheus::Terminal.instance.stderr).handle_error(e) # lol end else # todo: need to just return error instead of raise msg = "'#{command_name}' is not a morpheus command." suggestions = find_command_suggestions(command_name) if suggestions && suggestions.size == 1 msg += "\nThe most similar command is:\n" msg += "\t" + suggestions.first + "\n" elsif suggestions && suggestions.size > 1 msg += "\nThe most similar commands are:\n" suggestions.first(50).each do |suggestion| msg += "\t" + suggestion + "\n" end end #raise CommandNotFoundError.new(msg) result = Morpheus::Cli::ErrorHandler.new(Morpheus::Terminal.instance.stderr).handle_error(CommandNotFoundError.new(msg)) # lol end return result end
exec_expression(input)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 126 def exec_expression(input) # puts "exec_expression(#{input})" flow = input if input.is_a?(String) begin flow = Morpheus::Cli::ExpressionParser.parse(input) rescue Morpheus::Cli::ExpressionParser::InvalidExpression => e raise e end end # puts "executing flow: #{flow.inspect}" final_command_result = nil if flow.size == 0 # no input eh? else last_command_result = nil if ['&&','||', '|'].include?(flow.first) raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "#{Morpheus::Terminal.angry_prompt}invalid command format, begins with an operator: #{input}" elsif ['&&','||', '|'].include?(flow.last) raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "#{Morpheus::Terminal.angry_prompt}invalid command format, ends with an operator: #{input}" # elsif ['&&','||', '|'].include?(flow.last) # raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "invalid command format, consecutive operators: #{cmd}" else #Morpheus::Logging::DarkPrinter.puts "Executing command flow: #{flow.inspect}" if Morpheus::Logging.debug? previous_command = nil previous_command_result = nil current_operator = nil still_executing = true # need to error before executing anything, could be dangerous otherwise! # also maybe only pass flow commands if they have a space on either side.. if flow.include?("|") raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "The PIPE (|) operator is not yet supported. You can wrap your arguments in quotations." end flow.each do |flow_cmd| if still_executing if flow_cmd == '&&' # AND operator current_operator = flow_cmd exit_code, cmd_err = parse_command_result(previous_command_result) if exit_code != 0 still_executing = false end elsif flow_cmd == '||' # or with previous command current_operator = flow_cmd exit_code, err = parse_command_result(previous_command_result) if exit_code == 0 still_executing = false end elsif flow_cmd == '|' # or with previous command # todo, handle pipe! raise Morpheus::Cli::ExpressionParser::InvalidExpression.new "The PIPE (|) operator is not yet supported. You can wrap your arguments in quotations." previous_command_result = nil still_executing = false # or just continue? elsif flow_cmd.is_a?(Array) # this is a subexpression, execute it as such current_operator = nil previous_command_result = exec_expression(flow_cmd) else # it's a command, not an operator current_operator = nil flow_argv = Shellwords.shellsplit(flow_cmd) previous_command_result = exec_command(flow_argv[0], flow_argv[1..-1]) end previous_command = flow_cmd else #Morpheus::Logging::DarkPrinter.puts "operator skipped command: #{flow_cmd}" if Morpheus::Logging.debug? end # previous_command = flow_cmd end final_command_result = previous_command_result end end return final_command_result end
find_command_suggestions(command_name)
click to toggle source
find suggested commands (or aliases) for a name that was not found First this looks for the plural of the original guess Then pop characters off the end looking for partial matches as long as the guess is at least 3 characters
# File lib/morpheus/cli/cli_registry.rb, line 304 def find_command_suggestions(command_name) every_command = cached_command_list guess = command_name suggestions = [] while suggestions.empty? && guess.size >= 3 plural_guess = guess.pluralize if every_command.include?(guess) suggestions << guess end if every_command.include?(plural_guess) suggestions << plural_guess end # if every_command.include?(guess) # suggestions << plural_guess # else guess_regexp = /^#{Regexp.escape(guess)}/i every_command.each do |it| if it =~ guess_regexp suggestions << it end end # end guess = guess[0..-2] end suggestions.uniq! suggestions.sort! { |x,y| [x.split('-').size, x] <=> [y.split('-').size, y] } return suggestions end
has_alias?(alias_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 218 def has_alias?(alias_name) if alias_name.nil? || alias_name == '' false else !instance.get_alias(alias_name).nil? end end
has_command?(command_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 210 def has_command?(command_name) if command_name.nil? || command_name == '' false else !instance.get(command_name).nil? end end
instance()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 70 def instance @instance ||= CliRegistry.new end
new()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 19 def initialize @commands = {} # this is command => Class that includes ::CliCommand @aliases = {} # this is alias => String full input string end
parse_alias_definition(input)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 246 def parse_alias_definition(input) # todo: one multi group regex would work alias_name, command_string = nil, nil chunks = input.to_s.sub(/^alias\s+/, "").split('=') alias_name = chunks.shift command_string = chunks.compact.reject {|it| it.empty? }.join('=') command_string = command_string.strip.sub(/^'/, "").sub(/'\Z/, "").strip return alias_name, command_string end
parse_command_result(cmd_result)
click to toggle source
parse any object into a command result [exit_code, error] 0 means success. This treats nil, true, or an object as success ie. [0, nil] and false is treated as an error [1, error] @return [Array] [exit_code, error]. Success returns [0, nil].
# File lib/morpheus/cli/cli_registry.rb, line 261 def parse_command_result(cmd_result) exit_code, error = nil, nil if cmd_result.is_a?(Array) exit_code = cmd_result[0] || 0 error = cmd_result[1] elsif cmd_result.is_a?(Hash) exit_code = cmd_result[:exit_code] || 0 error = cmd_result[:error] || cmd_result[:err] elsif cmd_result == nil || cmd_result == true exit_code = 0 elsif cmd_result == false exit_code = 1 elsif cmd_result.is_a?(Integer) exit_code = cmd_result elsif cmd_result.is_a?(Float) exit_code = cmd_result.to_i elsif cmd_result.is_a?(String) exit_code = cmd_result.to_i else if cmd_result.respond_to?(:to_i) exit_code = cmd_result.to_i else # happens for aliases right now.. and execution flow probably, need to handle Array # uncomment to track them down, proceed with exit 0 for now #Morpheus::Logging::DarkPrinter.puts "debug: command #{command_name} produced an unexpected result: (#{cmd_result.class}) #{cmd_result}" if Morpheus::Logging.debug? exit_code = 0 end end return exit_code, error end
Public Instance Methods
add(cmd_name, klass)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 37 def add(cmd_name, klass) @commands[cmd_name.to_sym] = klass end
add_alias(alias_name, command_string)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 53 def add_alias(alias_name, command_string) #return @commands[alias_name.to_sym] if self.class.has_command?(alias_name) raise BadAlias.new "alias name '#{alias_name}' is invalid. That is the name of a morpheus command." elsif alias_name.to_s.downcase.strip == command_string.to_s.downcase.strip raise BadAlias.new "alias #{alias_name}=#{command_string} is invalid..." end @aliases[alias_name.to_sym] = command_string end
all()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 29 def all @commands.reject {|cmd, klass| klass.hidden_command } end
all_aliases()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 45 def all_aliases @aliases end
flush()
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 24 def flush @commands = {} @aliases = {} end
get(cmd_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 33 def get(cmd_name) @commands[cmd_name.to_sym] end
get_alias(alias_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 49 def get_alias(alias_name) @aliases[alias_name.to_sym] end
remove(cmd_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 41 def remove(cmd_name) @commands.delete(cmd_name.to_sym) end
remove_alias(alias_name)
click to toggle source
# File lib/morpheus/cli/cli_registry.rb, line 63 def remove_alias(alias_name) @aliases.delete(alias_name.to_sym) end