fuelcell 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +15 -0
  2. data/.codeclimate.yml +12 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +5 -0
  5. data/.travis.yml +15 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +51 -0
  10. data/Rakefile +5 -0
  11. data/bin/console +9 -0
  12. data/bin/example.rb +9 -0
  13. data/bin/setup +7 -0
  14. data/bin/test +20 -0
  15. data/bin/world.rb +6 -0
  16. data/fuelcell.gemspec +26 -0
  17. data/lib/fuelcell/action/arg_definition.rb +36 -0
  18. data/lib/fuelcell/action/arg_results.rb +57 -0
  19. data/lib/fuelcell/action/args_manager.rb +66 -0
  20. data/lib/fuelcell/action/callable.rb +54 -0
  21. data/lib/fuelcell/action/command.rb +72 -0
  22. data/lib/fuelcell/action/not_found.rb +55 -0
  23. data/lib/fuelcell/action/opt_definition.rb +79 -0
  24. data/lib/fuelcell/action/opt_results.rb +68 -0
  25. data/lib/fuelcell/action/opts_manager.rb +80 -0
  26. data/lib/fuelcell/action/root.rb +76 -0
  27. data/lib/fuelcell/action/subcommands.rb +81 -0
  28. data/lib/fuelcell/action.rb +11 -0
  29. data/lib/fuelcell/cli.rb +89 -0
  30. data/lib/fuelcell/help/base_formatter.rb +24 -0
  31. data/lib/fuelcell/help/builder.rb +71 -0
  32. data/lib/fuelcell/help/cmds_formatter.rb +57 -0
  33. data/lib/fuelcell/help/desc_formatter.rb +21 -0
  34. data/lib/fuelcell/help/opts_formatter.rb +62 -0
  35. data/lib/fuelcell/help/usage_formatter.rb +88 -0
  36. data/lib/fuelcell/help.rb +27 -0
  37. data/lib/fuelcell/parser/arg_handler.rb +31 -0
  38. data/lib/fuelcell/parser/base_handler.rb +133 -0
  39. data/lib/fuelcell/parser/cmd_args_strategy.rb +28 -0
  40. data/lib/fuelcell/parser/ignore_handler.rb +25 -0
  41. data/lib/fuelcell/parser/opt_handler.rb +58 -0
  42. data/lib/fuelcell/parser/opt_name_handler.rb +89 -0
  43. data/lib/fuelcell/parser/opt_value_equal_handler.rb +26 -0
  44. data/lib/fuelcell/parser/parsing_strategy.rb +80 -0
  45. data/lib/fuelcell/parser/short_opt_no_space_handler.rb +54 -0
  46. data/lib/fuelcell/parser.rb +4 -0
  47. data/lib/fuelcell/shell.rb +102 -0
  48. data/lib/fuelcell/version.rb +3 -0
  49. data/lib/fuelcell.rb +114 -0
  50. metadata +148 -0
@@ -0,0 +1,88 @@
1
+ module Fuelcell
2
+ module Help
3
+ # Formats help text to be displayed on the command line. The formatter
4
+ # works with help text structured in a hash.
5
+ class UsageFormatter < BaseFormatter
6
+
7
+ def call(data)
8
+ usage = data[:usage] || {}
9
+ text = format_cmd(usage)
10
+ opts = format_opts(usage[:opts], text.size + 1)
11
+ text += ' ' + opts unless opts.empty?
12
+
13
+ "#{text}\n"
14
+ end
15
+
16
+ # Format the options so that they wrap at the max width of the terminal
17
+ # and that they align after the command path.
18
+ #
19
+ # @param opts [Hash]
20
+ # @param align [Int]
21
+ # @return [String]
22
+ def format_opts(opts, align_width)
23
+ text = ''
24
+ line_width = align_width
25
+ opts.each do |opt|
26
+ text, line_width = append_opts(text, opt, line_width, align_width)
27
+ end
28
+ text.strip
29
+ end
30
+
31
+ # Format the label and the path which make the up
32
+ # the first line of usage text.
33
+ #
34
+ # @param data [Hash]
35
+ # @return [Array] formatted text, size of text
36
+ def format_cmd(data)
37
+ "#{data[:label]} #{data[:path]}"
38
+ end
39
+
40
+ # Append a single opt text to the usage line. Ensure wrapping
41
+ # occurs correctly & wrapped opt aligns with the start of the
42
+ # first opt.
43
+ #
44
+ # The align width is the amount of padding necessary in order to align
45
+ # all the opt text from the left.
46
+ #
47
+ # @param text [String] text of all currently appended options
48
+ # @param opt [String] text of the current option
49
+ # @param line_width [Int] width of the current line including padding
50
+ # @param align_width [Int] opts will align to this width after wrapping
51
+ def append_opts(text, opt, line_width, align_width)
52
+ str = opt_display(opt)
53
+ if (line_width + str.size) < max_width
54
+ return append_current_line(text, str, line_width)
55
+ end
56
+
57
+ append_nextline(text, str, align_width)
58
+ end
59
+
60
+ # Used to append to the usage line when its shorted then the terminal
61
+ # window
62
+ #
63
+ # @param text [String] the current usage line
64
+ # @param str [String] the string to be appended
65
+ # @param line_width [Int] width of current line
66
+ # @return [Array] append text & size
67
+ def append_current_line(text, str, line_width)
68
+ line_width += str.size + 1
69
+ text << str + ' '
70
+ [text, line_width]
71
+ end
72
+
73
+ # Used append a newline to the usage and wrap the text because it
74
+ # is long then the terminal width
75
+ #
76
+ def append_nextline(text, str, align_width)
77
+ text = text.strip + "\n"
78
+ text << (' ' * align_width) + str
79
+ [text, text.size]
80
+ end
81
+
82
+ def opt_display(data)
83
+ text = "#{short_opt(data)} #{long_opt(data)}".strip
84
+ "[#{text}]"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,27 @@
1
+ require 'fuelcell/help/builder'
2
+ require 'fuelcell/help/base_formatter'
3
+ require 'fuelcell/help/usage_formatter'
4
+ require 'fuelcell/help/opts_formatter'
5
+ require 'fuelcell/help/cmds_formatter'
6
+ require 'fuelcell/help/desc_formatter'
7
+
8
+ module Fuelcell
9
+ module Help
10
+ class << self
11
+ def generate(root, args = [], width = 80)
12
+ data = Builder.new.call(root, args)
13
+ text = UsageFormatter.new(width: width).call(data)
14
+
15
+ line = DescFormatter.new(width: width).call(data)
16
+ text << "\n" + line unless line.empty?
17
+
18
+ line = OptsFormatter.new(width: width).call(data)
19
+ text << "\n" + line unless line.empty?
20
+
21
+ line = CmdsFormatter.new(width: width).call(data)
22
+ text << "\n" + line unless line.empty?
23
+ text
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ module Fuelcell
2
+ module Parser
3
+ # Parse args based on command definitions & cast the value into the correct
4
+ # type. This will leave us with the args array (its values modified by the
5
+ # command definitions) and an args hash with its keys derived from the
6
+ # definition. Boths theses lists are needed to create the ArgResult which
7
+ # is returned
8
+ class ArgHandler < BaseHandler
9
+ SKIP = '__FUELCELL_SKIP_ARG__'
10
+ # @param cmd [Fuelcell::Command]
11
+ # @param args [Array] raw args from ARGV
12
+ # @return [Fuelcell::Action::ArgsResults]
13
+ def call(cmd, args)
14
+ list = {}
15
+ manager = cmd.args
16
+ manager.each_with_index do |arg, index|
17
+ value = args.fetch(index) {
18
+ fail "argument at #{index} is required" if arg.required?
19
+ arg.default? ? arg.default : SKIP
20
+ }
21
+ next if value == SKIP
22
+ args[index] = cast(arg.type, value)
23
+ # assign a pointer to the casted value
24
+ list[arg.name] = index
25
+ end
26
+
27
+ Fuelcell::Action::ArgResults.new(args, list)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,133 @@
1
+ module Fuelcell
2
+ module Parser
3
+ # Parsing the command line involves a command object, raw args array and
4
+ # the final options hash. Handlers use the command object to determine
5
+ # specifications on options and args, they will add and remove raw args
6
+ # and add to the options hash. This class provides helper methods used
7
+ # to encapsulate the command tasks needed by every handler
8
+ class BaseHandler
9
+
10
+ # Anything that does not start with an "-" is considered an arg
11
+ # nil is not considered an arg or an opt, since all elements in
12
+ # ARGV are strings
13
+ #
14
+ # @param text [String] represents an element from ARGV
15
+ # @return [Boolean]
16
+ def arg?(text)
17
+ return false if text.nil?
18
+ !text.to_s.start_with?('-')
19
+ end
20
+
21
+ # Search for an opt definition in the given command object
22
+ #
23
+ # @param cmd [Fuelcell::Command] command found on the cli
24
+ # @param name [String] name of the object
25
+ # @return [Fuelcell::OptDefinition]
26
+ def find_opt(cmd, name)
27
+ opt = cmd.find_opt(name)
28
+ fail "option #{name} is not registered" unless opt
29
+ opt
30
+ end
31
+
32
+ # Allows handlers to match the first raw arg against a
33
+ # regex or someother condition and if it fails that arg
34
+ # will be put back into the raw args otherwise the handler
35
+ # will process it
36
+ #
37
+ # params arg [String]
38
+ # returns [Boolean, String]
39
+ def take_first_arg(args)
40
+ arg = args.shift
41
+ unless yield arg
42
+ args.unshift arg
43
+ return false
44
+ end
45
+ arg
46
+ end
47
+
48
+ # Assigns opt name and value into the opts hash. It provides a common
49
+ # place for validation checks and casting.
50
+ #
51
+ # @param opts [Hash] holds processed opts
52
+ # @param opt [Fuelcell::OptDefinition]
53
+ # @param value [String] value found in raw_args
54
+ # @param raw_arg [String] used for error msg, the actual opt string
55
+ # @return the casted value
56
+ def assign_opt_value(opts, opt, value, raw_arg)
57
+ fail "#{raw_arg} is a flag and can not accept values" if opt.flag?
58
+
59
+ opts[opt.name] = cast(opt.type, value)
60
+ end
61
+
62
+ def cast_numeric(value)
63
+ unless value =~ /[-+]?\d*\.\d+|\d+/
64
+ fail ArgumentError, "expecting a numeric type, '#{value}' is invalid"
65
+ end
66
+ value.index('.') ? value.to_f : value.to_i
67
+ end
68
+
69
+ def cast_bool(value)
70
+ case value.to_s.downcase
71
+ when 'true', 'yes', '1' then true
72
+ when 'false', 'no', '0' then false
73
+ else
74
+ fail ArgumentError, "expecting bool value like " +
75
+ "(true,false,yes,no,1,0), #{value} is invalid"
76
+ end
77
+ end
78
+
79
+ # Collect all values in raw args upto the first option and put then
80
+ # into an array
81
+ #
82
+ # @params value [String] the first value of the array
83
+ # @params raw_args [Array] raw args used to collect remaining items
84
+ # @return [Array]
85
+ def cast_array(value)
86
+ value.to_s.split(',')
87
+ end
88
+
89
+ # A hash key value pair is assumed to be in the form key:value. Collect
90
+ # all args that are not opts and process them.
91
+ #
92
+ # @param value [String] the first key value pair
93
+ # @param raw_args [Array] raw args to collect remaining hash values
94
+ # @return [Hash]
95
+ def cast_hash(value)
96
+ list = cast_array(value)
97
+ result = {}
98
+ list.each do |item|
99
+ key, value = item.split(':', 2)
100
+ result[key] = value
101
+ end
102
+
103
+ result
104
+ end
105
+
106
+ # Delegate the cast based on type
107
+ #
108
+ # @param type [Symbol]
109
+ # @param value [String]
110
+ # @param raw_args [Array]
111
+ # @return casted value
112
+ def cast(type, value)
113
+ case type
114
+ when :numeric then cast_numeric(value)
115
+ when :bool then cast_bool(value)
116
+ when :hash then cast_hash(value)
117
+ when :array then cast_array(value)
118
+ else
119
+ value.to_s
120
+ end
121
+ end
122
+
123
+ # A flag has a value of true when its found
124
+ #
125
+ # @param opts [Hash] processed opts
126
+ # @param opt [Fuelcell::OptDefinition]
127
+ # @return [Boolean]
128
+ def found_opt_flag(opts, opt)
129
+ opts[opt.name] = true
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,28 @@
1
+ module Fuelcell
2
+ module Parser
3
+ class CmdArgsStrategy
4
+
5
+ # Extract arguments that form the command to be executed.
6
+ #
7
+ # This will collect all arguments up to the first option or the ignore
8
+ # symbol --. It separates and returns the command args as an array of
9
+ # strings that form a heirarchal route to the command. These command args
10
+ # are removed from the raw arg list
11
+ #
12
+ #
13
+ # @param [Array] raw args from ARGV
14
+ # @return <Array>
15
+ def call(args)
16
+ cmd_args = []
17
+ while item = args.shift
18
+ if item.start_with?('-')
19
+ args.unshift(item)
20
+ break
21
+ end
22
+ cmd_args << item
23
+ end
24
+ cmd_args
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module Fuelcell
2
+ module Parser
3
+ # Removes any args after the string '--' is found in the raw_args. It also
4
+ # removes the ignore string itself from the raw args.
5
+ #
6
+ # @param raw_args [Array] list of args usually from ARGV
7
+ # @return [Array]
8
+ class IgnoreHandler
9
+ def call(raw_args)
10
+ unless raw_args.is_a?(Array)
11
+ fail ArgumentError, 'raw args must be an array'
12
+ end
13
+
14
+ ignores = []
15
+ index = raw_args.index('--')
16
+ return ignores unless index
17
+
18
+ ignores = raw_args.slice!(index, raw_args.size)
19
+ # remove the ignore symbol --
20
+ ignores.shift
21
+ ignores
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,58 @@
1
+ module Fuelcell
2
+ module Parser
3
+ # Process options that are flags or use another arg as their value. This
4
+ # handles both short and long options. Flags are assigned a value of true
5
+ # while all other values are casted during value assignment
6
+ class OptHandler < BaseHandler
7
+ # @param cmd [Fuelcell::Command]
8
+ # @param args [Array] raw args from ARGV
9
+ # @param opts [Hash] stores the found opts
10
+ # @return [Boolean]
11
+ def call(cmd, args, opts)
12
+ arg = take_first_arg(args) do |text|
13
+ !(text =~ /^(--\w+(?:-\w+)*|-[a-zA-Z])$/).nil?
14
+ end
15
+ return false unless arg
16
+
17
+ opt = find_opt(cmd, arg)
18
+ return true if handled_flag?(opts, opt)
19
+
20
+ # We know we are not a flag, so we are expecting a value.
21
+ # We also know there are no other values available so for now
22
+ # this is considered a failure condition
23
+ fail_value_required(opt) if args.empty?
24
+
25
+ handle_value(opts, opt, arg, args)
26
+ true
27
+ end
28
+
29
+ private
30
+
31
+ def handle_value(opts, opt, arg, args)
32
+ value = args.shift
33
+ unless arg?(value)
34
+ if opt.default?
35
+ value = opt.default
36
+ else
37
+ fail_value_required(opt)
38
+ end
39
+ end
40
+
41
+ assign_opt_value(opts, opt, value, arg)
42
+ end
43
+
44
+ def handled_flag?(opts, opt)
45
+ return false unless opt.flag?
46
+ found_opt_flag(opts, opt)
47
+ true
48
+ end
49
+
50
+ def fail_value_required(opt)
51
+ return if opt.callable? || opt.cmd_path?
52
+
53
+ cli_opts = opt.cli_labels.join(' or ')
54
+ fail "value not found for #{cli_opts} when value is required"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,89 @@
1
+ module Fuelcell
2
+ module Parser
3
+ class OptNameHandler
4
+ # Parses the option defintiion name according to a set of rules that
5
+ # allows a short hand to be used to give the option name, its cli
6
+ # long & short names. The names are separated by |
7
+ #
8
+ # specify all 3: <opt name>|<cli long>|<cli short>
9
+ # when manually specifying all three the opt name is
10
+ # always first
11
+ # ex) version-opt|version|v
12
+ #
13
+ # specify 2: <cli long>|<cli short>
14
+ # <cli short>|<cli long>
15
+ # <opt name>|<cli long>
16
+ # when specifying 2 the opt name & cli long will be the same
17
+ # if one of the given names is a cli short
18
+ # ex) version|v
19
+ # ex) v|version
20
+ # ex) version-opt|version - only opt name and cli long are set
21
+ #
22
+ # specify 1: <cli-long>
23
+ # <cli-short>
24
+ # ex) v - cli short and opt name will be the same, no
25
+ # cli longs will be set
26
+ # ex) version - cli long and opt name will be the same, no
27
+ # cli short will be set
28
+ #
29
+ #
30
+ # @param name [String]
31
+ def call(text)
32
+ text = text.to_s
33
+ fail ArgumentError, 'option name can not be empty' if text.empty?
34
+
35
+ parts = text.split('|')
36
+ method_name = "manually_assign_#{parts.size}"
37
+ name, long, short = send(method_name, parts)
38
+
39
+ if !short.nil? && short.size > 1
40
+ fail ArgumentError, "option short name (#{short}) can only be 1 char"
41
+ end
42
+
43
+ [name, long, short]
44
+ end
45
+
46
+ private
47
+
48
+ def manually_assign_3(names)
49
+ if names[0].size == 1
50
+ fail ArgumentError,
51
+ 'short name can not be first when setting all 3 names'
52
+ end
53
+
54
+ if names[1].size > 1
55
+ name, long, short = names[0..2]
56
+ else
57
+ name, short, long = names[0..2]
58
+ end
59
+ [name, long, short]
60
+ end
61
+
62
+ def manually_assign_2(names)
63
+ name, long = names[0..1]
64
+ short = nil
65
+ if names.last.size == 1
66
+ long, short = names[0..1]
67
+ name = long
68
+ elsif names.first.size == 1
69
+ short, long = names[0..1]
70
+ name = long
71
+ end
72
+ [name, long, short]
73
+ end
74
+
75
+ def manually_assign_1(names)
76
+ name = names.first
77
+ if name.size == 1
78
+ short = name
79
+ long = nil
80
+ else
81
+ long = name
82
+ short = nil
83
+ end
84
+
85
+ [name, long, short]
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,26 @@
1
+ module Fuelcell
2
+ module Parser
3
+ class OptValueEqualHandler < BaseHandler
4
+
5
+ # Handle options both long and short that express their value using an
6
+ # equal sign like --foo=bar or -f=bar
7
+ #
8
+ # @param cmd [Fuelcell::Command]
9
+ # @param args [Array] raw args from ARGV
10
+ # @param opts [Hash] stores the found opts
11
+ # @return [Boolean]
12
+ def call(cmd, args, opts)
13
+ return false unless take_first_arg(args) do |arg|
14
+ !!(arg =~ /^(--\w+(?:-\w+)*|-[a-zA-Z])=(.*)$/)
15
+ end
16
+
17
+ name = $1
18
+ value = $2
19
+
20
+ opt = find_opt(cmd, name)
21
+ assign_opt_value(opts, opt, value, name)
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,80 @@
1
+ require_relative 'ignore_handler'
2
+ require_relative 'opt_value_equal_handler'
3
+ require_relative 'short_opt_no_space_handler'
4
+ require_relative 'opt_handler'
5
+ require_relative 'arg_handler'
6
+
7
+ module Fuelcell
8
+ module Parser
9
+ class ParsingStrategy < BaseHandler
10
+ attr_reader :ignore_handler, :opt_handlers, :arg_handler
11
+
12
+ # Arrange all the handlers in the correct order for this
13
+ # strategy.The order is as follows:
14
+ # 1. short clusters
15
+ # 2. opts using equals
16
+ # 3. short opts that have no space between them and their value
17
+ # 4. all other option conditions
18
+ # 5. check that all required options have been processed.
19
+ #
20
+ # The check for required options is designed to be handled last
21
+ def initialize
22
+ @ignore_handler = IgnoreHandler.new
23
+ @opt_handlers = [
24
+ ShortOptNoSpaceHandler.new,
25
+ OptValueEqualHandler.new,
26
+ OptHandler.new
27
+ ]
28
+
29
+ @arg_handler = ArgHandler.new
30
+ end
31
+
32
+ # Run all handlers in order, in a continuous loop until all raw args
33
+ # are empty. Handlers implement the call method as a strategy pattern
34
+ # so they all have the same signature. During the loop and after all
35
+ # the handlers have run, we check the first arg, if it's not an opt
36
+ # it means it's a arg so we move it to the args array. This
37
+ # process continues until there are no other args. Required options
38
+ # are not inforced for the help command
39
+ #
40
+ # @param cmd [Fuelcell::Command]
41
+ # @param raw_args [Array] raw args from ARGV
42
+ # @param opts [Hash] stores processed options
43
+ # @return [Array] the process options and processed args
44
+ def call(cmd, raw_args, opts = Fuelcell::Action::OptResults.new)
45
+ ignores = ignore_handler.call(raw_args)
46
+ args = run_option_handlers(cmd, raw_args, opts)
47
+ args = arg_handler.call(cmd, args)
48
+ unless cmd.name == 'help'
49
+ cmd.missing_opts(opts.keys) do |missing|
50
+ fail "option [#{missing.first.cli_names}] is required"
51
+ end
52
+ end
53
+
54
+ format_return(cmd, opts, args, ignores)
55
+ end
56
+
57
+ private
58
+
59
+ def run_option_handlers(cmd, raw_args, opts)
60
+ args = []
61
+ until raw_args.empty?
62
+ opt_handlers.each do |handler|
63
+ break if handler.call(cmd, raw_args, opts)
64
+ end
65
+ args << raw_args.shift if arg?(raw_args.first)
66
+ end
67
+ args
68
+ end
69
+
70
+ def format_return(cmd, opts, args, ignores)
71
+ {
72
+ cmd: cmd,
73
+ opts: opts,
74
+ args: args,
75
+ ignores: ignores
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,54 @@
1
+ module Fuelcell
2
+ module Parser
3
+ # Handles short options that express their value without using a space like
4
+ # -uroot where the short opt is -u and value is root
5
+ class ShortOptNoSpaceHandler < BaseHandler
6
+ # @param cmd [Fuelcell::Command]
7
+ # @param args [Array] raw args from ARGV
8
+ # @param opts [Hash] stores the found opts
9
+ # @return [Boolean]
10
+ def call(cmd, args, opts)
11
+ arg = take_first_arg(args) do |text|
12
+ !(text =~ /^-([a-zA-Z]{2,})$/).nil?
13
+ end
14
+ return false unless arg
15
+
16
+ return true if handle_no_space_value(cmd, opts, args, arg)
17
+
18
+ arg[0] = '' # remove the dash
19
+ handle_cluster(cmd, opts, arg)
20
+
21
+ true
22
+ end
23
+
24
+ private
25
+
26
+ # we need to determine if this is a short opt with a value
27
+ # smushed into it or a cluster of opts
28
+ def handle_no_space_value(cmd, opts, args, arg)
29
+ name = "-#{arg[1]}"
30
+ value = arg.slice(2, arg.size)
31
+ opt = cmd.find_opt(name)
32
+
33
+ fail "#{name} is not a registered option" unless opt
34
+
35
+ unless opt.flag?
36
+ assign_opt_value(opts, opt, value, name)
37
+ return true
38
+ end
39
+ false
40
+ end
41
+
42
+ def handle_cluster(cmd, opts, arg)
43
+ cluster = arg.split('')
44
+ cluster.each do |short|
45
+ opt = cmd.find_opt("-#{short}")
46
+ unless opt.flag?
47
+ fail "-#{short} can not live in a cluster, it must be a flag"
48
+ end
49
+ found_opt_flag(opts, opt)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,4 @@
1
+ require 'fuelcell/parser/base_handler'
2
+ require 'fuelcell/parser/ignore_handler'
3
+ require 'fuelcell/parser/parsing_strategy'
4
+ require 'fuelcell/parser/cmd_args_strategy'