Йордан обнови решението на 07.11.2016 23:22 (преди около 8 години)
+
+def parse_raw_option(raw_opt)
+ re = /^((-[[:alpha:]])(.+)|(--[[:alpha:]]*)=(.+))$/
+ parsed = re.match raw_opt
+
+ if parsed
+ name_place = 2
+ name_place += 2 unless parsed[name_place] != nil
+ { name: parsed[name_place], param: parsed[name_place + 1] }
+ else
+ { name: raw_opt, param: true }
+ end
+end
+
+class CommandParser
+ def initialize(name)
+ @command_name = name
+ @arguments = []
+ @options_info = []
+ @option_blocks = {}
+ end
+
+ def argument(arg, &block)
+ @arguments << { name: arg, block: block }
+ end
+
+ def option(short, long, label, &block)
+ @options_info << { short: short, long: long, label: label }
+ @option_blocks["-#{short}"] = block
+ @option_blocks["--#{long}"] = block
+ end
+
+ def option_with_parameter(short, long, label, placeholder, &block)
+ @options_info << {
+ short: short,
+ long: long,
+ label: label,
+ placeholder: placeholder
+ }
+ @option_blocks["-#{short}"] = block
+ @option_blocks["--#{long}"] = block
+ end
+
+ def parse(runner, params)
+ passed_args = params.select { |param| detect_agr param }
+ passed_opts = params.select { |param| detect_opt param }
+ apply_args runner, passed_args
+ apply_opts runner, passed_opts
+ end
+
+ def detect_agr(arg)
+ /^[[[:alpha:]]0-9_\.]*$/.match arg
+ end
+
+ def apply_args(runner, args)
+ args.each_with_index do |arg, index|
+ @arguments[index][:block].call(runner, arg)
+ end
+ end
+
+ def detect_opt(opt)
+ /^-.*$/.match opt
+ end
+
+ def apply_opts(runner, opts)
+ opts.each do |raw_opt|
+ opt = parse_raw_option raw_opt
+ if @option_blocks.key? opt[:name]
+ @option_blocks[opt[:name]].call(runner, opt[:param])
+ end
+ end
+ end
+
+ def help
+ args = @arguments.reduce("") { |memo, arg| "#{memo} [#{arg[:name]}]" }
+ opts = @options_info.map do |opt|
+ param = "=#{opt[:placeholder]}" if opt.key? :placeholder
+ " -#{opt[:short]}, --#{opt[:long]}#{param} #{opt[:label]}"
+ end.reduce("") { |memo, opt| "#{memo}\n#{opt}" }
+ "Usage: #{@command_name}#{args}#{opts}"
+ end
+end