Калина обнови решението на 07.11.2016 06:08 (преди около 8 години)
+class CommandParser
+
+ def initialize(command_name)
+ @command_name = command_name
+ @argument_map = {}
+ @option_map = {}
+ end
+
+ def argument(argument_name, &block)
+ @argument_map[argument_name] = block
+ end
+
+ def option(*option_name, &block)
+ option_name[0] = '-' + option_name[0]
+ option_name[1] = '--' + option_name[1]
+ @option_map[option_name] = block
+ end
+
+ def option_with_parameter(*option_name, &block)
+ option(*option_name, &block)
+ end
+
+ def parse(command_runner, argv)
+ options = argv.select { |arg| arg.start_with?("-", "--") }
+ arguments = argv.reject { |arg| options.include?(arg) }
+ parse_options(command_runner, options)
+ @argument_map.each_with_index do |(_, block), index|
+ block.call(command_runner, arguments[index])
+ end
+ end
+
+ def parse_options(command_runner, options)
+ @option_map.each_with_index do |(opt, block), index|
+ if opt.include? (options[index])
+ block.call(command_runner, true)
+ else
+ parse_option_parameter(command_runner, options[index], opt, block)
+ end
+ end
+ end
+
+ def parse_option_parameter(command_runner, option, opt, block)
+ if option.include? "="
+ block.call(command_runner, option.sub(/^-*#{opt[1]}=/, ""))
+ else
+ block.call(command_runner, option.sub(/^-*#{opt[0]}/, ""))
+ end
+ end
+
+ def help
+ banner = "Usage: #{@command_name} "
+ @argument_map.each do |key, _|
+ banner << "[#{key}] "
+ end
+ banner.strip + generate_help_body
+ end
+
+ def generate_help_body
+ body = ""
+ @option_map.each do |key, _|
+ if key.size == 4
+ key[1] = key[1] + "=" + key[3]
+ key.slice!(3)
+ end
+ body << "\n #{key[0]}, #{key[1]} #{key[2]}"
+ end
+ body
+ end
+end