File: command_line_parser.rb

package info (click to toggle)
ruby-fission 0.5.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 624 kB
  • sloc: ruby: 4,664; makefile: 10
file content (189 lines) | stat: -rw-r--r-- 5,113 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
module Fission

  class CommandLineParser

    # Internal: Creates a new Fission::CommandLineParser object.
    #
    # args - The command line arguments to parse.  This is expected to be in the
    # same format of ARGV (Array) (default: ARGV).
    #
    # Examples:
    #
    #   CommandLineParser.new ['foo', 'bar']
    #
    #   CommandLineParser.new
    #
    # Returns a Fission::CommandLineParser object.
    def initialize(args=ARGV)
      @args = args

      gather_commands_and_summaries

      setup_options_parser
    end

    # Internal: Parses the command line arguments.  If the arguments are
    # invalid, the appropriate help will be output and then will exit.  If the
    # arguments are valid, then the @command variable will be set to a new
    # instance of the determined command class.
    #
    # Examples:
    #
    #   @command_line_parser.parse
    #
    # Returns nothing.
    def parse
      @options_parser.order! @args

      determine_command_provided
      self
    rescue OptionParser::InvalidOption => e
      ui.output e
      show_all_help
      exit 1
    end

    # Internal: Accessor for an instance of the determined command. This is set
    # by running the parse method.
    #
    # Examples:
    #
    #   @command_line_parser.command
    #
    # Returns an instance of the determined command if the arguments are valid.
    # Returns nil if the parse command has not yet been run.
    def command
      @command
    end

    private
    # Internal: Sets up the base option parser.
    #
    # Examples:
    #
    #   @cli.setup_option_parser
    #
    # Returns nothing.  This will set the @option_parser instance variable.
    def setup_options_parser
      @options_parser = OptionParser.new do |opts|
        opts.banner = "\nUsage: fission [options] COMMAND [arguments]"

        opts.on_head('-v', '--version', 'Output the version of fission') do
          ui.output VERSION
          exit 0
        end

        opts.on_head('-h', '--help', 'Displays this message') do
          show_all_help
          exit 0
        end
      end
    end

    # Internal: Provides the help of all of the known commands.
    #
    # Examples
    #
    #   @cli.commands_help
    #
    # Outputs the summary text for all known commands.
    def commands_help
      longest_cmd = @commands.inject do |longest, cmd_name|
        longest.length > cmd_name.length ? longest : cmd_name
      end

      ui.output "\nCommands:"

      Hash[@command_names_and_summaries.sort].each_pair do |name, summary|
        ui.output_printf "%-#{longest_cmd.length}s      %s\n", name, summary
      end
    end

    # Internal: Determines all of the available commands and their summaries.
    #
    # Examples
    #
    #   @cli.command_names_and_summaries
    #   # => { 'clone' => 'Clones a VM', 'stop' => 'Stops a VM' }
    #
    # Returns nothing.  This will set the @command_names_and_summaries instance
    # variable with the result.
    def gather_commands_and_summaries
      @command_names_and_summaries = Command.descendants.inject({}) do |result, klass|
        cmd = klass.new
        result[cmd.command_name] = cmd.summary
        result
      end

      @commands = @command_names_and_summaries.keys.sort
    end

    # Internal: Determines the command that has been provided.  If it is
    # determined that an invalid command is provided, then the help/usage will
    # be displayed and it will exit.
    #
    # Examples:
    #
    #   @cli.determine_command_to_execute
    #
    # Returns nothing.  This will set the @command instance variable to an instance
    # of the appropriate command class (assuming it is valid).
    def determine_command_provided
      if @commands.include? @args.first
        @command = Command.const_get(@args.first.capitalize).new @args.drop 1
      elsif is_snapshot_command?
        klass = @args.take(2).map {|c| c.capitalize}.join('')
        @command = Command.const_get(klass).new @args.drop 2
      else
        show_all_help
        exit 1
      end
    end

    # Internal: Determines if the provided command is a snapshot related
    # command.  This will use the @args instance variable to make the
    # determination.
    #
    # Examples
    #
    #   @cli.is_snapshot_command? ['foo', 'bar']
    #   # => false
    #
    #   @cli.is_snapshot_command? ['snapshot', 'list']
    #   # => true
    #
    # Returns a Boolean of whether a snapshot command was given or not.
    def is_snapshot_command?
      @args.first == 'snapshot' &&
      @args.count > 1 &&
      @commands.include?(@args.take(2).join(' '))
    end

    # Internal: Outputs the usage as well as the known commands and their
    # summaries.
    #
    # Examples
    #
    #   @cli.show_all_help
    #   # => 'fission options command arguments ....'
    #
    # Returns nothing.
    def show_all_help
      ui.output @options_parser
      commands_help
    end

    # Internal: Helper method for outputting text to the ui
    #
    # Examples
    #
    #   @cli.ui.output 'foo'
    #
    # Returns a UI instance.
    def ui
      @ui ||= UI.new
    end

  end

end