Решение на Трета задача - Четене на командни аргументи от Мартин Христов

Обратно към всички решения

Към профила на Мартин Христов

Резултати

  • 2 точки от тестове
  • 0 бонус точки
  • 2 точки общо
  • 5 успешни тест(а)
  • 10 неуспешни тест(а)

Код

class CommandParserBase
def initialize(command_name)
@command_name = command_name
@operations = []
@arguments = []
@options = {}
@options_with_params = {}
end
protected
def handle_option_with_param(command_runner, name)
if name.include? "="
option = (name.split "=")[0]
argument = (name.split "=")[1]
else
option = @options_with_params[name.slice 0, 2]
argument = name.slice 2, name.size
end
@options_with_params[option]["block"].call command_runner, argument
end
def handle_option_without_param(command_runner, name)
name = @options[name] unless full_name_option? name
@options[name]["block"].call command_runner, true
end
def handle_option(command_runner, name)
if with_param? name
handle_option_with_param command_runner, name
else
handle_option_without_param command_runner, name
end
end
end
class CommandParser < CommandParserBase
def initialize(command_name)
super(command_name)
end
def argument(file_name, &block)
@operations << block
@arguments << file_name
end
def option(short_name, full_name, description, &block)
option = {}
add_options(option, @options, short_name, full_name, description, &block)
end
def option_with_parameter(short_name, full_name,
description, placeholder, &block
)
option_with_param = { "placeholder" => placeholder }
add_options(
option_with_param, @options_with_params,
short_name, full_name, description, &block
)
end
def parse(command_runner, argv)
argument_index = 0
argv.each_index do |index|
if option? argv[index]
handle_option command_runner, argv[index]
else
@operations[argument_index].call command_runner, argv[index]
argument_index += 1
end
end
end
def help
CommandParserHelper.new(
@command_name, @arguments, @options, @options_with_params
).help
end
private
def option?(name)
name.start_with? "-"
end
def full_name_option?(name)
name.start_with? "--"
end
def with_param?(name)
(name.include? "=") || (@options.key? (name.slice 0, 2))
end
def add_options(current_option, all_options, short_name,
full_name, description, &block
)
current_option["short_name"] = "-" + short_name
current_option["full_name"] = "--" + full_name
current_option["description"] = description
current_option["block"] = block
all_options["-" + short_name] = "--" + full_name
all_options["--" + full_name] = current_option
end
end
class CommandParserHelper
def initialize(command_name, arguments, options, options_with_params)
@command_name = command_name
@arguments = arguments
@options = options
@options_with_params = options_with_params
end
def help
result = "Usage: #{@command_name} ["
@arguments.each { |arg| result += arg }
result += "]\n "
result += options_help
result += options_with_params_help
result
end
private
def options_help
result = ""
@options.keys.each_slice(2) do |pair|
result += "#{pair[0]}, #{pair[1]} "
result += "#{@options[pair[1]]['description']}\n "
end
result
end
def options_with_params_help
result = ""
@options_with_params.keys.each_slice(2) do |pair|
result += "#{pair[0]}, #{pair[1]}="
result += "#{@options_with_params[pair[1]]['placeholder']} "
result += "#{@options_with_params[pair[1]]['description']}\n"
end
result
end
end

Лог от изпълнението

..F.FF.FFFFF.FF

Failures:

  1) CommandParser#option parses a single option in short form
     Failure/Error: parser.parse(command_runner, %w(-a))
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20161113-27983-3bhbh7/solution.rb:19:in `handle_option_with_param'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:29:in `handle_option'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:65:in `block in parse'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `each_index'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `parse'
     # /tmp/d20161113-27983-3bhbh7/spec.rb:55:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  2) CommandParser#option parses multiple options
     Failure/Error: parser.parse(command_runner, %w(--directory -a))
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20161113-27983-3bhbh7/solution.rb:19:in `handle_option_with_param'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:29:in `handle_option'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:65:in `block in parse'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `each_index'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `parse'
     # /tmp/d20161113-27983-3bhbh7/spec.rb:75:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  3) CommandParser#option_with_parameter parses a option with parameter in short format
     Failure/Error: parser.parse(command_runner, %w(-stime))
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20161113-27983-3bhbh7/solution.rb:24:in `handle_option_without_param'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:31:in `handle_option'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:65:in `block in parse'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `each_index'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `parse'
     # /tmp/d20161113-27983-3bhbh7/spec.rb:87:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  4) CommandParser#help shows basic usage message
     Failure/Error: expect(parser.help).to eq 'Usage: ls'
       
       expected: "Usage: ls"
            got: "Usage: ls []\n    "
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,3 @@
       -Usage: ls
       +Usage: ls []
       +    
     # /tmp/d20161113-27983-3bhbh7/spec.rb:104:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  5) CommandParser#help shows single argument
     Failure/Error: expect(parser.help).to eq 'Usage: ls [FILE]'
       
       expected: "Usage: ls [FILE]"
            got: "Usage: ls [FILE]\n    "
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,3 @@
        Usage: ls [FILE]
       +    
     # /tmp/d20161113-27983-3bhbh7/spec.rb:110:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  6) CommandParser#help shows multiple arguments
     Failure/Error: expect(parser.help).to eq 'Usage: ls [FIRST FILE] [SECOND FILE] [THIRD FILE]'
       
       expected: "Usage: ls [FIRST FILE] [SECOND FILE] [THIRD FILE]"
            got: "Usage: ls [FIRST FILESECOND FILETHIRD FILE]\n    "
       
       (compared using ==)
       
       Diff:
       @@ -1,2 +1,3 @@
       -Usage: ls [FIRST FILE] [SECOND FILE] [THIRD FILE]
       +Usage: ls [FIRST FILESECOND FILETHIRD FILE]
       +    
     # /tmp/d20161113-27983-3bhbh7/spec.rb:118:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  7) CommandParser#help shows single option help
     Failure/Error: expect(options_help_messages(parser)).to match_array([
       expected collection contained:  ["    -a, --all do not ignore entries starting with ."]
       actual collection contained:    ["    ", "    -a, --all do not ignore entries starting with ."]
       the extra elements were:        ["    "]
     # /tmp/d20161113-27983-3bhbh7/spec.rb:125:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  8) CommandParser#help shows multiple options help
     Failure/Error: expect(options_help_messages(parser)).to match_array([
       expected collection contained:  ["    -a, --all do not ignore entries starting with .", "    -d, --directory list directories themselves, not their contents"]
       actual collection contained:    ["    ", "    -a, --all do not ignore entries starting with .", "    -d, --directory list directories themselves, not their contents"]
       the extra elements were:        ["    "]
     # /tmp/d20161113-27983-3bhbh7/spec.rb:137:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  9) CommandParser when having options with and without values and parameters parses all the options and arguments correctly
     Failure/Error: parser.parse(command_runner, %w(--all -d -ssize first.rb second.rb))
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20161113-27983-3bhbh7/solution.rb:19:in `handle_option_with_param'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:29:in `handle_option'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:65:in `block in parse'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `each_index'
     # /tmp/d20161113-27983-3bhbh7/solution.rb:63:in `parse'
     # /tmp/d20161113-27983-3bhbh7/spec.rb:169:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

  10) CommandParser when having options with and without values and parameters generates a correct help usage
     Failure/Error: expect(header).to eq 'Usage: ls [FIRST FILE] [SECOND FILE]'
       
       expected: "Usage: ls [FIRST FILE] [SECOND FILE]"
            got: "Usage: ls [FIRST FILESECOND FILE]"
       
       (compared using ==)
     # /tmp/d20161113-27983-3bhbh7/spec.rb:182:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:7:in `block (2 levels) in <top (required)>'

Finished in 0.00934 seconds
15 examples, 10 failures

Failed examples:

rspec /tmp/d20161113-27983-3bhbh7/spec.rb:51 # CommandParser#option parses a single option in short form
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:69 # CommandParser#option parses multiple options
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:83 # CommandParser#option_with_parameter parses a option with parameter in short format
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:103 # CommandParser#help shows basic usage message
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:107 # CommandParser#help shows single argument
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:113 # CommandParser#help shows multiple arguments
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:121 # CommandParser#help shows single option help
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:130 # CommandParser#help shows multiple options help
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:168 # CommandParser when having options with and without values and parameters parses all the options and arguments correctly
rspec /tmp/d20161113-27983-3bhbh7/spec.rb:180 # CommandParser when having options with and without values and parameters generates a correct help usage

История (1 версия и 0 коментара)

Мартин обнови решението на 06.11.2016 20:52 (преди над 7 години)

+class CommandParserBase
+ def initialize(command_name)
+ @command_name = command_name
+ @operations = []
+ @arguments = []
+ @options = {}
+ @options_with_params = {}
+ end
+
+ protected
+ def handle_option_with_param(command_runner, name)
+ if name.include? "="
+ option = (name.split "=")[0]
+ argument = (name.split "=")[1]
+ else
+ option = @options_with_params[name.slice 0, 2]
+ argument = name.slice 2, name.size
+ end
+ @options_with_params[option]["block"].call command_runner, argument
+ end
+
+ def handle_option_without_param(command_runner, name)
+ name = @options[name] unless full_name_option? name
+ @options[name]["block"].call command_runner, true
+ end
+
+ def handle_option(command_runner, name)
+ if with_param? name
+ handle_option_with_param command_runner, name
+ else
+ handle_option_without_param command_runner, name
+ end
+ end
+end
+
+class CommandParser < CommandParserBase
+ def initialize(command_name)
+ super(command_name)
+ end
+
+ def argument(file_name, &block)
+ @operations << block
+ @arguments << file_name
+ end
+
+ def option(short_name, full_name, description, &block)
+ option = {}
+ add_options(option, @options, short_name, full_name, description, &block)
+ end
+
+ def option_with_parameter(short_name, full_name,
+ description, placeholder, &block
+ )
+ option_with_param = { "placeholder" => placeholder }
+ add_options(
+ option_with_param, @options_with_params,
+ short_name, full_name, description, &block
+ )
+ end
+
+ def parse(command_runner, argv)
+ argument_index = 0
+ argv.each_index do |index|
+ if option? argv[index]
+ handle_option command_runner, argv[index]
+ else
+ @operations[argument_index].call command_runner, argv[index]
+ argument_index += 1
+ end
+ end
+ end
+
+ def help
+ CommandParserHelper.new(
+ @command_name, @arguments, @options, @options_with_params
+ ).help
+ end
+
+ private
+ def option?(name)
+ name.start_with? "-"
+ end
+
+ def full_name_option?(name)
+ name.start_with? "--"
+ end
+
+ def with_param?(name)
+ (name.include? "=") || (@options.key? (name.slice 0, 2))
+ end
+
+ def add_options(current_option, all_options, short_name,
+ full_name, description, &block
+ )
+ current_option["short_name"] = "-" + short_name
+ current_option["full_name"] = "--" + full_name
+ current_option["description"] = description
+ current_option["block"] = block
+
+ all_options["-" + short_name] = "--" + full_name
+ all_options["--" + full_name] = current_option
+ end
+end
+
+class CommandParserHelper
+ def initialize(command_name, arguments, options, options_with_params)
+ @command_name = command_name
+ @arguments = arguments
+ @options = options
+ @options_with_params = options_with_params
+ end
+
+ def help
+ result = "Usage: #{@command_name} ["
+ @arguments.each { |arg| result += arg }
+ result += "]\n "
+ result += options_help
+ result += options_with_params_help
+ result
+ end
+
+ private
+ def options_help
+ result = ""
+ @options.keys.each_slice(2) do |pair|
+ result += "#{pair[0]}, #{pair[1]} "
+ result += "#{@options[pair[1]]['description']}\n "
+ end
+ result
+ end
+
+ def options_with_params_help
+ result = ""
+ @options_with_params.keys.each_slice(2) do |pair|
+ result += "#{pair[0]}, #{pair[1]}="
+ result += "#{@options_with_params[pair[1]]['placeholder']} "
+ result += "#{@options_with_params[pair[1]]['description']}\n"
+ end
+ result
+ end
+end