gli_aziz_light 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +17 -0
  6. data/CONTRIBUTING.md +23 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +201 -0
  9. data/ObjectModel.graffle +1191 -0
  10. data/README.rdoc +109 -0
  11. data/Rakefile +126 -0
  12. data/bin/gli +59 -0
  13. data/bin/report_on_rake_results +10 -0
  14. data/bin/test_all_rubies.sh +6 -0
  15. data/features/gli_executable.feature +90 -0
  16. data/features/gli_init.feature +232 -0
  17. data/features/step_definitions/gli_executable_steps.rb +18 -0
  18. data/features/step_definitions/gli_init_steps.rb +11 -0
  19. data/features/step_definitions/todo_steps.rb +88 -0
  20. data/features/support/env.rb +53 -0
  21. data/features/todo.feature +413 -0
  22. data/features/todo_legacy.feature +128 -0
  23. data/gli.cheat +95 -0
  24. data/gli.gemspec +34 -0
  25. data/gli.rdoc +73 -0
  26. data/lib/gli.rb +35 -0
  27. data/lib/gli/app.rb +286 -0
  28. data/lib/gli/app_support.rb +341 -0
  29. data/lib/gli/command.rb +171 -0
  30. data/lib/gli/command_finder.rb +41 -0
  31. data/lib/gli/command_line_option.rb +34 -0
  32. data/lib/gli/command_line_token.rb +63 -0
  33. data/lib/gli/command_support.rb +181 -0
  34. data/lib/gli/commands/compound_command.rb +42 -0
  35. data/lib/gli/commands/doc.rb +231 -0
  36. data/lib/gli/commands/help.rb +95 -0
  37. data/lib/gli/commands/help_modules/arg_name_formatter.rb +20 -0
  38. data/lib/gli/commands/help_modules/command_finder.rb +60 -0
  39. data/lib/gli/commands/help_modules/command_help_format.rb +156 -0
  40. data/lib/gli/commands/help_modules/global_help_format.rb +70 -0
  41. data/lib/gli/commands/help_modules/help_completion_format.rb +31 -0
  42. data/lib/gli/commands/help_modules/list_formatter.rb +23 -0
  43. data/lib/gli/commands/help_modules/one_line_wrapper.rb +18 -0
  44. data/lib/gli/commands/help_modules/options_formatter.rb +49 -0
  45. data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
  46. data/lib/gli/commands/help_modules/tty_only_wrapper.rb +23 -0
  47. data/lib/gli/commands/help_modules/verbatim_wrapper.rb +16 -0
  48. data/lib/gli/commands/initconfig.rb +74 -0
  49. data/lib/gli/commands/rdoc_document_listener.rb +116 -0
  50. data/lib/gli/commands/scaffold.rb +401 -0
  51. data/lib/gli/dsl.rb +226 -0
  52. data/lib/gli/exceptions.rb +71 -0
  53. data/lib/gli/flag.rb +68 -0
  54. data/lib/gli/gli_option_block_parser.rb +84 -0
  55. data/lib/gli/gli_option_parser.rb +156 -0
  56. data/lib/gli/option_parser_factory.rb +81 -0
  57. data/lib/gli/option_parsing_result.rb +21 -0
  58. data/lib/gli/options.rb +23 -0
  59. data/lib/gli/switch.rb +35 -0
  60. data/lib/gli/terminal.rb +101 -0
  61. data/lib/gli/version.rb +5 -0
  62. data/test/apps/README.md +2 -0
  63. data/test/apps/todo/Gemfile +2 -0
  64. data/test/apps/todo/README.rdoc +6 -0
  65. data/test/apps/todo/Rakefile +23 -0
  66. data/test/apps/todo/bin/todo +63 -0
  67. data/test/apps/todo/lib/todo/commands/create.rb +24 -0
  68. data/test/apps/todo/lib/todo/commands/list.rb +63 -0
  69. data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
  70. data/test/apps/todo/lib/todo/commands/make.rb +52 -0
  71. data/test/apps/todo/lib/todo/version.rb +3 -0
  72. data/test/apps/todo/test/tc_nothing.rb +14 -0
  73. data/test/apps/todo/todo.gemspec +23 -0
  74. data/test/apps/todo/todo.rdoc +5 -0
  75. data/test/apps/todo_legacy/Gemfile +2 -0
  76. data/test/apps/todo_legacy/README.rdoc +6 -0
  77. data/test/apps/todo_legacy/Rakefile +23 -0
  78. data/test/apps/todo_legacy/bin/todo +61 -0
  79. data/test/apps/todo_legacy/lib/todo/commands/create.rb +24 -0
  80. data/test/apps/todo_legacy/lib/todo/commands/list.rb +63 -0
  81. data/test/apps/todo_legacy/lib/todo/commands/ls.rb +47 -0
  82. data/test/apps/todo_legacy/lib/todo/version.rb +3 -0
  83. data/test/apps/todo_legacy/test/tc_nothing.rb +14 -0
  84. data/test/apps/todo_legacy/todo.gemspec +23 -0
  85. data/test/apps/todo_legacy/todo.rdoc +5 -0
  86. data/test/apps/todo_plugins/commands/third.rb +1 -0
  87. data/test/config.yaml +10 -0
  88. data/test/fake_std_out.rb +30 -0
  89. data/test/init_simplecov.rb +8 -0
  90. data/test/option_test_helper.rb +13 -0
  91. data/test/tc_command.rb +508 -0
  92. data/test/tc_compound_command.rb +22 -0
  93. data/test/tc_doc.rb +325 -0
  94. data/test/tc_flag.rb +62 -0
  95. data/test/tc_gli.rb +773 -0
  96. data/test/tc_help.rb +387 -0
  97. data/test/tc_options.rb +43 -0
  98. data/test/tc_subcommand_parsing.rb +104 -0
  99. data/test/tc_subcommands.rb +260 -0
  100. data/test/tc_switch.rb +55 -0
  101. data/test/tc_terminal.rb +100 -0
  102. data/test/tc_verbatim_wrapper.rb +36 -0
  103. data/test/test_helper.rb +20 -0
  104. metadata +330 -0
@@ -0,0 +1,226 @@
1
+ module GLI
2
+ # The primary DSL for GLI. This represents the methods shared between your top-level app and
3
+ # the commands. See GLI::Command for additional methods that apply only to command objects.
4
+ module DSL
5
+ # Describe the next switch, flag, or command. This should be a
6
+ # short, one-line description
7
+ #
8
+ # +description+:: A String of the short descripiton of the switch, flag, or command following
9
+ def desc(description); @next_desc = description; end
10
+ alias :d :desc
11
+
12
+ # Provide a longer, more detailed description. This
13
+ # will be reformatted and wrapped to fit in the terminal's columns
14
+ #
15
+ # +long_desc+:: A String that is s longer description of the switch, flag, or command following.
16
+ def long_desc(long_desc); @next_long_desc = long_desc; end
17
+
18
+ # Describe the argument name of the next flag. It's important to keep
19
+ # this VERY short and, ideally, without any spaces (see Example).
20
+ #
21
+ # +name+:: A String that *briefly* describes the argument given to the following command or flag.
22
+ # +options+:: Symbol or array of symbols to annotate this argument. This doesn't affect parsing, just
23
+ # the help output. Values recognized are:
24
+ # +:optional+:: indicates this argument is optional; will format it with square brackets
25
+ # +:multiple+:: indicates multiple values are accepted; will format appropriately
26
+ #
27
+ # Example:
28
+ # desc 'Set the filename'
29
+ # arg_name 'file_name'
30
+ # flag [:f,:filename]
31
+ #
32
+ # Produces:
33
+ # -f, --filename=file_name Set the filename
34
+ def arg_name(name,options=[])
35
+ @next_arg_name = name
36
+ @next_arg_options = options
37
+ end
38
+
39
+ # set the default value of the next flag or switch
40
+ #
41
+ # +val+:: The default value to be used for the following flag if the user doesn't specify one
42
+ # and, when using a config file, the config also doesn't specify one. For a switch, this is
43
+ # the value to be used if the switch isn't specified on the command-line. Note that if you
44
+ # set a switch to have a default of true, using the switch on the command-line has no effect.
45
+ # To disable a switch where the default is true, use the <tt>--no-</tt> form.
46
+ def default_value(val); @next_default_value = val; end
47
+
48
+ # Create a flag, which is a switch that takes an argument
49
+ #
50
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
51
+ # and aliases for this flag. The last element can be a hash of options:
52
+ # +:desc+:: the description, instead of using #desc
53
+ # +:long_desc+:: the long_description, instead of using #long_desc
54
+ # +:default_value+:: the default value, instead of using #default_value
55
+ # +:arg_name+:: the arg name, instead of using #arg_name
56
+ # +:must_match+:: A regexp that the flag's value must match
57
+ # +:type+:: A Class (or object you passed to GLI::App#accept) to trigger type coversion
58
+ #
59
+ # Example:
60
+ #
61
+ # desc 'Set the filename'
62
+ # flag [:f,:filename,'file-name']
63
+ #
64
+ # flag :ipaddress, :desc => "IP Address", :must_match => /\d+\.\d+\.\d+\.\d+/
65
+ #
66
+ # flag :names, :desc => "list of names", :type => Array
67
+ #
68
+ # Produces:
69
+ #
70
+ # -f, --filename, --file-name=arg Set the filename
71
+ def flag(*names)
72
+ options = extract_options(names)
73
+ names = [names].flatten
74
+
75
+ verify_unused(names)
76
+ flag = Flag.new(names,options)
77
+ flags[flag.name] = flag
78
+
79
+ clear_nexts
80
+ flags_declaration_order << flag
81
+ flag
82
+ end
83
+ alias :f :flag
84
+
85
+ # Create a switch, which is a command line flag that takes no arguments (thus, it _switches_ something on)
86
+ #
87
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
88
+ # and aliases for this switch. The last element can be a hash of options:
89
+ # +:desc+:: the description, instead of using #desc
90
+ # +:long_desc+:: the long_description, instead of using #long_desc
91
+ # +:default_value+:: if the switch is omitted, use this as the default value. By default, switches default to off, or +false+
92
+ # +:negatable+:: if true, this switch will get a negatable form (e.g. <tt>--[no-]switch</tt>, false it will not. Default is true
93
+ def switch(*names)
94
+ options = extract_options(names)
95
+ names = [names].flatten
96
+
97
+ verify_unused(names)
98
+ switch = Switch.new(names,options)
99
+ switches[switch.name] = switch
100
+
101
+ clear_nexts
102
+ switches_declaration_order << switch
103
+ switch
104
+ end
105
+ alias :s :switch
106
+
107
+ def clear_nexts # :nodoc:
108
+ @next_desc = nil
109
+ @next_arg_name = nil
110
+ @next_arg_options = nil
111
+ @next_default_value = nil
112
+ @next_long_desc = nil
113
+ end
114
+
115
+ # Define a new command. This can be done in a few ways, but the most common method is
116
+ # to pass a symbol (or Array of symbols) representing the command name (or names) and a block.
117
+ # The block will be given an instance of the Command that was created.
118
+ # You then may call methods on this object to define aspects of that Command.
119
+ #
120
+ # Alternatively, you can call this with a one element Hash, where the key is the symbol representing the name
121
+ # of the command, and the value being an Array of symbols representing the commands to call in order, as a
122
+ # chained or compound command. Note that these commands must exist already, and that only those command-specific
123
+ # options defined in *this* command will be parsed and passed to the chained commands. This might not be what you expect
124
+ #
125
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names and aliases
126
+ # for this command *or* a Hash, as described above.
127
+ #
128
+ # ==Examples
129
+ #
130
+ # # Make a command named list
131
+ # command :list do |c|
132
+ # c.action do |global_options,options,args|
133
+ # # your command code
134
+ # end
135
+ # end
136
+ #
137
+ # # Make a command named list, callable by ls as well
138
+ # command [:list,:ls] do |c|
139
+ # c.action do |global_options,options,args|
140
+ # # your command code
141
+ # end
142
+ # end
143
+ #
144
+ # # Make a command named all, that calls list and list_contexts
145
+ # command :all => [ :list, :list_contexts ]
146
+ #
147
+ # # Make a command named all, aliased as :a:, that calls list and list_contexts
148
+ # command [:all,:a] => [ :list, :list_contexts ]
149
+ #
150
+ def command(*names)
151
+ command_options = {
152
+ :description => @next_desc,
153
+ :arguments_name => @next_arg_name,
154
+ :arguments_options => @next_arg_options,
155
+ :long_desc => @next_long_desc,
156
+ :skips_pre => @skips_pre,
157
+ :skips_post => @skips_post,
158
+ :skips_around => @skips_around,
159
+ }
160
+ @commands_declaration_order ||= []
161
+ if names.first.kind_of? Hash
162
+ command = GLI::Commands::CompoundCommand.new(self,
163
+ names.first,
164
+ command_options)
165
+ command.parent = self
166
+ commands[command.name] = command
167
+ @commands_declaration_order << command
168
+ else
169
+ new_command = Command.new(command_options.merge(:names => [names].flatten))
170
+ command = commands[new_command.name]
171
+ if command.nil?
172
+ command = new_command
173
+ command.parent = self
174
+ commands[command.name] = command
175
+ @commands_declaration_order << command
176
+ end
177
+ yield command
178
+ end
179
+ clear_nexts
180
+ end
181
+ alias :c :command
182
+
183
+ def flags_declaration_order # :nodoc:
184
+ @flags_declaration_order ||= []
185
+ end
186
+
187
+ def switches_declaration_order # :nodoc:
188
+ @switches_declaration_order ||= []
189
+ end
190
+
191
+
192
+ private
193
+ # Checks that the names passed in have not been used in another flag or option
194
+ def verify_unused(names) # :nodoc:
195
+ names.each do |name|
196
+ verify_unused_in_option(name,flags,"flag")
197
+ verify_unused_in_option(name,switches,"switch")
198
+ end
199
+ end
200
+
201
+ def verify_unused_in_option(name,option_like,type) # :nodoc:
202
+ return if name.to_s == 'help'
203
+ raise ArgumentError.new("#{name} has already been specified as a #{type} #{context_description}") if option_like[name]
204
+ option_like.each do |one_option_name,one_option|
205
+ if one_option.aliases
206
+ if one_option.aliases.include? name
207
+ raise ArgumentError.new("#{name} has already been specified as an alias of #{type} #{one_option_name} #{context_description}")
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ # Extract the options hash out of the argument to flag/switch and
214
+ # set the values if using classic style
215
+ def extract_options(names)
216
+ options = {}
217
+ options = names.pop if names.last.kind_of? Hash
218
+ options = { :desc => @next_desc,
219
+ :long_desc => @next_long_desc,
220
+ :default_value => @next_default_value,
221
+ :arg_name => @next_arg_name}.merge(options)
222
+ end
223
+
224
+
225
+ end
226
+ end
@@ -0,0 +1,71 @@
1
+ module GLI
2
+ # Mixed into all exceptions that GLI handles; you can use this to catch
3
+ # anything that came from GLI intentionally. You can also mix this into non-GLI
4
+ # exceptions to get GLI's exit behavior.
5
+ module StandardException
6
+ def exit_code; 1; end
7
+ end
8
+ # Indicates that the command line invocation was bad
9
+ class BadCommandLine < StandardError
10
+ include StandardException
11
+ def exit_code; 64; end
12
+ end
13
+
14
+ class PreconditionFailed < StandardError
15
+ include StandardException
16
+ def exit_code; 65; end
17
+ end
18
+
19
+ # Indicates the bad command line was an unknown command
20
+ class UnknownCommand < BadCommandLine
21
+ end
22
+
23
+ # The command issued partially matches more than one command
24
+ class AmbiguousCommand < BadCommandLine
25
+ end
26
+
27
+ # Indicates the bad command line was an unknown global argument
28
+ class UnknownGlobalArgument < BadCommandLine
29
+ end
30
+
31
+ class CommandException < BadCommandLine
32
+ # The command for which the argument was unknown
33
+ attr_reader :command_in_context
34
+ # +message+:: the error message to show the user
35
+ # +command+:: the command we were using to parse command-specific options
36
+ def initialize(message,command_in_context,exit_code=nil)
37
+ super(message)
38
+ @command_in_context = command_in_context
39
+ @exit_code = exit_code
40
+ end
41
+
42
+ def exit_code
43
+ @exit_code || super
44
+ end
45
+ end
46
+
47
+ # Indicates the bad command line was an unknown command argument
48
+ class UnknownCommandArgument < CommandException
49
+ end
50
+
51
+ # Raise this if you want to use an exit status that isn't the default
52
+ # provided by GLI. Note that GLI::App#exit_now! might be a bit more to your liking.
53
+ #
54
+ # Example:
55
+ #
56
+ # raise CustomExit.new("Not connected to DB",-5) unless connected?
57
+ # raise CustomExit.new("Bad SQL",-6) unless valid_sql?(args[0])
58
+ #
59
+ class CustomExit < StandardError
60
+ include StandardException
61
+ attr_reader :exit_code #:nodoc:
62
+ # Create a custom exit exception
63
+ #
64
+ # +message+:: String containing error message to show the user
65
+ # +exit_code+:: the exit code to use (as an Int), overridding GLI's default
66
+ def initialize(message,exit_code)
67
+ super(message)
68
+ @exit_code = exit_code
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,68 @@
1
+ require 'gli/command_line_option.rb'
2
+
3
+ module GLI
4
+ # Defines a flag, which is to say a switch that takes an argument
5
+ class Flag < CommandLineOption # :nodoc:
6
+
7
+ # Regexp that is used to see if the flag's argument matches
8
+ attr_reader :must_match
9
+
10
+ # Type to which we want to cast the values
11
+ attr_reader :type
12
+
13
+ # Name of the argument that user configured
14
+ attr_reader :argument_name
15
+
16
+ # Creates a new option
17
+ #
18
+ # names:: Array of symbols or strings representing the names of this switch
19
+ # options:: hash of options:
20
+ # :desc:: the short description
21
+ # :long_desc:: the long description
22
+ # :default_value:: the default value of this option
23
+ # :arg_name:: the name of the flag's argument, default is "arg"
24
+ # :must_match:: a regexp that the flag's value must match
25
+ # :type:: a class to convert the value to
26
+ # :mask:: if true, the default value of this flag will not be output in the help.
27
+ # This is useful for password flags where you might not want to show it
28
+ # on the command-line.
29
+ def initialize(names,options)
30
+ super(names,options)
31
+ @argument_name = options[:arg_name] || "arg"
32
+ @default_value = options[:default_value]
33
+ @must_match = options[:must_match]
34
+ @type = options[:type]
35
+ @mask = options[:mask]
36
+ end
37
+
38
+ def safe_default_value
39
+ if @mask
40
+ "********"
41
+ else
42
+ default_value
43
+ end
44
+ end
45
+
46
+ def arguments_for_option_parser
47
+ args = all_forms_a.map { |name| "#{name} VAL" }
48
+ args << @must_match if @must_match
49
+ args << @type if @type
50
+ args
51
+ end
52
+
53
+ # Returns a string of all possible forms
54
+ # of this flag. Mostly intended for printing
55
+ # to the user.
56
+ def all_forms(joiner=', ')
57
+ forms = all_forms_a
58
+ string = forms.join(joiner)
59
+ if forms[-1] =~ /^\-\-/
60
+ string += '='
61
+ else
62
+ string += ' '
63
+ end
64
+ string += @argument_name
65
+ return string
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,84 @@
1
+ module GLI
2
+ # An "option block" is a set of parseable options, starting from the beginning of
3
+ # the argument list, stopping with the first unknown command-line element.
4
+ # This class handles parsing that block
5
+ class GLIOptionBlockParser
6
+
7
+ # Create the parser using the given +OptionParser+ instance and exception handling
8
+ # strategy.
9
+ #
10
+ # option_parser_factory:: An +OptionParserFactory+ instance, configured to parse wherever you are on the command line
11
+ # exception_klass_or_block:: means of handling exceptions from +OptionParser+. One of:
12
+ # an exception class:: will be raised on errors with a message
13
+ # lambda/block:: will be called with a single argument - the error message.
14
+ def initialize(option_parser_factory,exception_klass_or_block)
15
+ @option_parser_factory = option_parser_factory
16
+ @extra_error_context = nil
17
+ @exception_handler = if exception_klass_or_block.kind_of?(Class)
18
+ lambda { |message,extra_error_context|
19
+ raise exception_klass_or_block,message
20
+ }
21
+ else
22
+ exception_klass_or_block
23
+ end
24
+ end
25
+
26
+ # Parse the given argument list, returning the unparsed arguments and options hash of parsed arguments.
27
+ # Exceptions from +OptionParser+ are given to the handler configured in the constructor
28
+ #
29
+ # args:: argument list. This will be mutated
30
+ #
31
+ # Returns unparsed args
32
+ def parse!(args)
33
+ do_parse(args)
34
+ rescue OptionParser::InvalidOption => ex
35
+ @exception_handler.call("Unknown option #{ex.args.join(' ')}",@extra_error_context)
36
+ rescue OptionParser::InvalidArgument => ex
37
+ @exception_handler.call("#{ex.reason}: #{ex.args.join(' ')}",@extra_error_context)
38
+ end
39
+
40
+ protected
41
+
42
+ def do_parse(args)
43
+ first_non_option = nil
44
+ @option_parser_factory.option_parser.order!(args) do |non_option|
45
+ first_non_option = non_option
46
+ break
47
+ end
48
+ args.unshift(first_non_option)
49
+ end
50
+ end
51
+
52
+ class CommandOptionBlockParser < GLIOptionBlockParser
53
+
54
+ def command=(command_being_parsed)
55
+ @extra_error_context = command_being_parsed
56
+ end
57
+
58
+ protected
59
+
60
+ def break_on_non_option?
61
+ true
62
+ end
63
+
64
+ def do_parse(args)
65
+ unknown_options = []
66
+ @option_parser_factory.option_parser.order!(args) do |non_option|
67
+ unknown_options << non_option
68
+ break if break_on_non_option?
69
+ end
70
+ unknown_options.reverse.each do |unknown_option|
71
+ args.unshift(unknown_option)
72
+ end
73
+ args
74
+ end
75
+ end
76
+
77
+ class LegacyCommandOptionBlockParser < CommandOptionBlockParser
78
+
79
+ protected
80
+ def break_on_non_option?
81
+ false
82
+ end
83
+ end
84
+ end