Class: Clin::CommandParser

Inherits:
Object
  • Object
show all
Defined in:
lib/clin/command_parser.rb

Overview

Command parser

Instance Method Summary collapse

Constructor Details

#initialize(command_cls, argv = ARGV, fallback_help: true) ⇒ CommandParser

Create the command parser

Parameters:

  • command_cls (Class<Clin::Command>)

    Command that must be matched

  • argv (Array<String>) (defaults to: ARGV)

    List of CL arguments

  • fallback_help (Boolean) (defaults to: true)

    If the parse should raise an HelpError or the real error.



9
10
11
12
13
14
# File 'lib/clin/command_parser.rb', line 9

def initialize(command_cls, argv = ARGV, fallback_help: true)
  @command = command_cls
  argv = Shellwords.split(argv) if argv.is_a? String
  @argv = argv
  @fallback_help = fallback_help
end

Instance Method Details

#handle_error(error) ⇒ Object

Guard that check if there was an error and fail HelpError if there was

Raises:



110
111
112
113
114
# File 'lib/clin/command_parser.rb', line 110

def handle_error(error)
  return unless error
  fail Clin::HelpError, @command.option_parser if @fallback_help
  fail error
end

#parseObject

Parse the command line.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/clin/command_parser.rb', line 17

def parse
  argv = @argv.clone
  error = nil
  options = {}
  begin
    options.merge! parse_options(argv)
  rescue Clin::OptionError => e
    error = e
  end
  begin
    options.merge! parse_arguments(argv)
  rescue Clin::ArgumentError => e
    raise e unless @fallback_help
    error = e
  end

  return redispatch(options) if @command.redispatch?
  obj = @command.new(options)
  handle_error(error)
  obj
end

#parse_arguments(argv) ⇒ Object

Parse the argument. The options must have been strip out first.



76
77
78
79
80
81
82
83
# File 'lib/clin/command_parser.rb', line 76

def parse_arguments(argv)
  out = {}
  @command.args.each do |arg|
    value, argv = arg.parse(argv)
    out[arg.name.to_sym] = value
  end
  out.delete_if { |_, v| v.nil? }
end

#parse_options(argv) ⇒ Array

Parse the options in the argv.

Returns:

  • (Array)

    the list of argv that are not options(positional arguments)



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/clin/command_parser.rb', line 41

def parse_options(argv)
  out = {}
  parser = @command.option_parser(out)
  skipped = skipped_options
  argv.reject! { |x| skipped.include?(x) }
  begin
    parser.parse!(argv)
  rescue OptionParser::InvalidOption => e
    raise Clin::OptionError, e.to_s
  end
  out[:skipped_options] = skipped if @command.skip_options?
  out
end

#redispatch(params) ⇒ Object

Method called after the argument have been parsed and before creating the command

Parameters:

  • params (Array<String>)

    Parsed params from the command line.



87
88
89
90
91
92
93
94
95
96
# File 'lib/clin/command_parser.rb', line 87

def redispatch(params)
  commands = @command._redispatch_args.last
  commands ||= @command.default_commands
  dispatcher = Clin::CommandDispatcher.new(commands)
  begin
    dispatcher.parse(redispatch_arguments(params))
  rescue Clin::HelpError
    raise Clin::HelpError, @command.option_parser
  end
end

#redispatch_arguments(params) ⇒ Object

Compute the list of argument to pass to the CommandDispatcher

Parameters:

  • params (Hash)

    Options and Arguments of the CL



100
101
102
103
104
105
106
# File 'lib/clin/command_parser.rb', line 100

def redispatch_arguments(params)
  args, prefix = @command._redispatch_args
  args = args.map { |x| params[x] }.flatten.compact
  args = prefix.split + args unless prefix.nil?
  args += params[:skipped_options] if @command.skip_options?
  args
end

#skipped_optionsObject

Get the options that have been skipped by options_first!



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/clin/command_parser.rb', line 56

def skipped_options
  return [] unless @command.skip_options?
  argv = @argv.dup
  skipped = []
  parser = @command.option_parser
  loop do
    begin
      parser.parse!(argv)
      break
    rescue OptionParser::InvalidOption => e
      skipped << e.to_s.sub(/invalid option:\s+/, '')
      next if argv.empty? || argv.first.start_with?('-')
      skipped << argv.shift
    end
  end

  skipped
end