choosy 0.4.9 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/Gemfile.lock +13 -1
  2. data/README.md +259 -0
  3. data/Rakefile +28 -17
  4. data/lib/VERSION.yml +4 -4
  5. data/lib/choosy.rb +38 -10
  6. data/lib/choosy/argument.rb +0 -2
  7. data/lib/choosy/base_command.rb +9 -8
  8. data/lib/choosy/command.rb +0 -6
  9. data/lib/choosy/converter.rb +0 -5
  10. data/lib/choosy/dsl/argument_builder.rb +0 -5
  11. data/lib/choosy/dsl/base_builder.rb +0 -2
  12. data/lib/choosy/dsl/base_command_builder.rb +54 -42
  13. data/lib/choosy/dsl/command_builder.rb +0 -6
  14. data/lib/choosy/dsl/option_builder.rb +4 -6
  15. data/lib/choosy/dsl/super_command_builder.rb +0 -4
  16. data/lib/choosy/errors.rb +10 -2
  17. data/lib/choosy/option.rb +0 -3
  18. data/lib/choosy/parse_result.rb +0 -2
  19. data/lib/choosy/parser.rb +0 -4
  20. data/lib/choosy/printing/base_printer.rb +0 -3
  21. data/lib/choosy/printing/color.rb +21 -33
  22. data/lib/choosy/printing/erb_printer.rb +0 -2
  23. data/lib/choosy/printing/formatting_element.rb +0 -2
  24. data/lib/choosy/printing/help_printer.rb +0 -3
  25. data/lib/choosy/printing/manpage.rb +5 -2
  26. data/lib/choosy/printing/manpage_printer.rb +1 -6
  27. data/lib/choosy/rake.rb +33 -31
  28. data/lib/choosy/super_command.rb +1 -7
  29. data/lib/choosy/super_parser.rb +0 -6
  30. data/lib/choosy/terminal.rb +0 -3
  31. data/lib/choosy/verifier.rb +0 -3
  32. data/lib/choosy/version.rb +0 -2
  33. data/spec/choosy/argument_spec.rb +0 -3
  34. data/spec/choosy/base_command_spec.rb +0 -3
  35. data/spec/choosy/command_spec.rb +0 -4
  36. data/spec/choosy/converter_spec.rb +0 -4
  37. data/spec/choosy/dsl/argument_builder_spec.rb +0 -3
  38. data/spec/choosy/dsl/base_builder_spec.rb +0 -3
  39. data/spec/choosy/dsl/base_command_builder_spec.rb +18 -5
  40. data/spec/choosy/dsl/commmand_builder_spec.rb +0 -6
  41. data/spec/choosy/dsl/option_builder_spec.rb +0 -3
  42. data/spec/choosy/dsl/super_command_builder_spec.rb +0 -4
  43. data/spec/choosy/option_spec.rb +0 -3
  44. data/spec/choosy/parser_spec.rb +0 -5
  45. data/spec/choosy/printing/base_printer_spec.rb +0 -5
  46. data/spec/choosy/printing/color_spec.rb +1 -4
  47. data/spec/choosy/printing/help_printer_spec.rb +0 -5
  48. data/spec/choosy/printing/manpage_printer_spec.rb +0 -4
  49. data/spec/choosy/printing/manpage_spec.rb +2 -3
  50. data/spec/choosy/super_command_spec.rb +0 -3
  51. data/spec/choosy/super_parser_spec.rb +0 -5
  52. data/spec/choosy/terminal_spec.rb +0 -3
  53. data/spec/choosy/verifier_spec.rb +0 -7
  54. data/spec/choosy/version_spec.rb +0 -2
  55. metadata +127 -121
  56. data/README.markdown +0 -463
  57. data/lib/choosy/printing.rb +0 -1
  58. data/spec/integration/command-A_spec.rb +0 -37
@@ -1,463 +0,0 @@
1
- # Choosy: Picking your Arguments Carefully
2
-
3
- This is a small DSL library for creating command line clients in Ruby. It is largely inspired by the <a href="https://github.com/defunkt/choice">choice</a>, <a href="https://github.com/visionmedia/commander">commander</a>, and <a href="http://furius.ca/optcomplete/">optcomplete.py</a> libraries, though it makes some different design decisions than they do. It is opinionated software.
4
-
5
- This library should:
6
-
7
- - Make creating command line clients relatively easy.
8
- - Make creating supercommands like git, subversion, and gem easier.
9
- - Allow you to add validation logic for your arguments within the parsing phase.
10
- - Allowing for dependencies between options, so that you can more easily validate related options (i.e. if the<code>--bold</code> flag requires the <code>--font Arial</code> flag, then you should be able to ask for the <code>--font</code> option to be validated first, and then the <code>--bold</code> option.
11
- - Allow you to customize its output using your own formatting system, or provide several convenient defaults when you don't want to provide your own.
12
-
13
- This library should never:
14
-
15
- - Interact with your execution logic. You can attach executors to commands for convenience, but the execution phase should be delegated to you, not the parsing library. Separation of concerns, people.
16
- - Rely on display or user interface libraries like Highline, since this is only for parsing command lines.
17
- - Pollute your namespaces with my DSL function names. (I really, really hate it when libraries do this.)
18
-
19
- # Examples
20
-
21
- #!/usr/bin/env ruby
22
- # foo.rb
23
- require 'choosy'
24
-
25
- FOO_VERSION = '1.0.1'
26
-
27
- class FooExecutor
28
- def execute!(args, options)
29
- puts "BOLDED!!" if options[:bold]
30
- options[:count].times do
31
- puts "#{options[:prefix]}#{options[:words].push('foo').join(',')}#{options[:suffix]}"
32
- end
33
- puts "and #{args.join ' '}"
34
- end
35
- end
36
-
37
- $foo_cmd = Choosy::Command.new :foo do |foo|
38
- # Add a class to do the execution when you call foo_cmd.execute!
39
- # You can also use a proc that takes the options and the args, like:
40
- # executor { |args, options| puts 'Hi!' }
41
- executor FooExecutor.new
42
-
43
- # When used as a subcommand, you need a summary for the help screen
44
- summary "This is a nice command named 'foo'"
45
-
46
- # You can add your custom printer by giving the
47
- # full path to an ERB template file here.
48
- # The default printer is :standard, but you can
49
- # also use the builtin printer :erb, with the :tempates
50
- # parameter to set the erb template you wish to use. The
51
- # output can be colored or uncolored, though the
52
- # default is colored.
53
- printer :standard, :color => true, :header_styles => [:bold, :green]
54
-
55
- para 'Prints out "foo" to the console'
56
- para 'This is a long description of what foo is an how it works. This line will assuredly wrap the console at least once, since it it such a long line, but it will be wrapped automatically by the printer, above. If you want to, you can add write "printer :standard, :max_width => 80" to set the maximum column width that the printer will allow (not respected by ERB templates).'
57
-
58
- header 'Required Options:' # Formatted according to the header_styles for the printer
59
-
60
- # A shorthand for a common option type.
61
- # It adds the '-p/--prefix PREFIX' infomation for you.
62
- single :prefix, "A prefix for 'foo'" do
63
- default '<'
64
- required
65
- end
66
-
67
- # The long way to do the same thing as above, except with
68
- # explicitly named dependencies
69
- option :suffix => [:prefix] do
70
- short '-s'
71
- long '--suffix', 'SUFFIX'
72
- desc 'A suffix for "foo"'
73
- required
74
-
75
- validate do |suffix, options|
76
- if suffix == options[:prefix]
77
- die "You can't matching prefixes and suffixes, you heathen!"
78
- end
79
- end
80
- end
81
-
82
- # Just like the 'single' method above, except now it automatically
83
- # requires/casts the argument to this flag into an integer. These commands
84
- # also take an optional hash as the last argument, which can be used instead
85
- # of a block.
86
- integer :count, 'The number of times to repeat "foo"', :required => true
87
-
88
- header 'Options:', :bold, :blue # Format this header differently, overrides 'header_styles'
89
-
90
- option :words do
91
- short '-w'
92
- long '--words', 'WORDS+' # By default, the '+' at the end
93
- # means that this takes multiple
94
- # arguments. You put a '-' at
95
- # the end of the argument list
96
- # to stop parsing this option
97
- # and allow for regular args.
98
- desc "Other fun words to put in quotes"
99
-
100
- # Sets the exact count of the number of arguments it accepts.
101
- # also allowable are the single selectors :zero and :one.
102
- # By default, the option 'WORDS+' sets the range to be
103
- # {:at_least => 1, :at_most => 1000 }
104
- count :at_least => 2, :at_most => 10
105
-
106
- validate do |words, options|
107
- words.each do |word|
108
- if word !~ /\w+/
109
- die "I can't print that: #{word}"
110
- end
111
- end
112
- end
113
- end
114
-
115
- # Alternatively, we could have done the following:
116
- strings :words, "Other fun words to put in quotes" do
117
- count 2..10
118
- default []
119
- validate do |words, options|
120
- words.each do |word|
121
- if word !~ /\w+/
122
- die "I can't print that: #{word}"
123
- end
124
- end
125
- end
126
- end
127
-
128
- # Yet another shorthand notation for options, since they
129
- # are boolean by default. Here, we add a negation to the
130
- # long flag of the option, creating [-b|--bold|--un-bold] flags.
131
- # By default, calling 'negate' in a block without an argument
132
- # uses the '--no-' prefix instead.
133
- boolean :bold, "Bold this option", :default => false, :negate => 'un'
134
-
135
- # Tail options
136
-
137
- # When any of the simpler notations are suffixed with a '_'
138
- # character, the short option is always suppressed.
139
- boolean_ :debug, "Prints out extra debugging output."
140
-
141
- # The '_' characters are replaced with '-' in flags, so the
142
- # following creates a '--[no-]color' flag.
143
- boolean_ :color, "Turns on/off coloring in the output. Defalt is on." do
144
- negate
145
- default true
146
- validate do
147
- foo.entity.alter do
148
- printer :standard, :colored => false
149
- end
150
- end
151
- end
152
-
153
- # Adds the standard -h/--help option.
154
- # Should skip the '-h' flag if already set.
155
- help # Automatically adds the description if not passed an argument. You can supply your own
156
-
157
- # Adds the --version option.
158
- version "Foo: #{FOO_VERSION}"
159
-
160
- # Now, add some validation for any addtional arguments
161
- # that are left over after the parsing the options.
162
- arguments do
163
- metaname 'ARGS'
164
- count 1..10
165
- validate do |args, options|
166
- if args.empty?
167
- die "You have to pass in empty arguments that do nothing!"
168
- end
169
- if args.count == 10
170
- die "Whoa there! You're going argument crazy!"
171
- end
172
- end
173
- end
174
- end
175
-
176
- if __FILE__ == $0
177
- # Parses and validates the options.
178
- args = ['--prefix', '{',
179
- '--suffix', '}',
180
- '--words', 'high', 'there', 'you', '-',
181
- # The '-' stops parsing this option, so that:
182
- 'handsom', 'devil',
183
- 'http://not.posting.here', # will be regular arguments
184
- '-c', '3', # Count
185
- '--', # Stops parsing all arguments
186
- '-h', '--help', '-v', '--version' # Ignored
187
- ]
188
- result = $foo_cmd.parse!(args)
189
-
190
- require 'pp'
191
- pp result[:prefix] # => '{'
192
- pp result[:suffix] # => '}'
193
- pp result[:count] # => 3
194
- pp result[:bold] # => false
195
- pp result[:words] # => ['high', 'there', 'you']
196
- pp result.args # => ['handsom', 'devil',
197
- # 'http://not.posting.here',
198
- # '-h', '--help', '-v', '--version']
199
- pp result.options # => {:prefix => '{', :suffix => '}'
200
- # :count => 3, :bold => false,
201
- # :words => ['high', 'there', 'you'],
202
- # :debug => false, :color => true}
203
-
204
- # Now, call the command that does the actual work.
205
- # This passes the foo_cmd.options and the foo_cmd.args
206
- # as arguments to the executors 'execute!' method.
207
- #
208
- # This allows you to easily associate command classes with
209
- # commands, without resorting to a hash or combining
210
- # execution logic with command parsing logic.
211
- $foo_cmd.execute!(args) # {high,there,you,foo}
212
- # {high,there,you,foo}
213
- # {high,there,you,foo}
214
- # and handsom devil http://not.posting.here -h --help -v --verbose
215
-
216
- end
217
-
218
- ### Super Commands
219
-
220
- You can also combine multiple choices into an uber-choice, creating commands that look a lot like git or subversion.
221
-
222
- First, we create another command.
223
-
224
- #!/usr/bin/env ruby
225
- # bar.rb
226
- require 'choosy'
227
-
228
- # Create a new command
229
- $bar_cmd = Choosy::Command.new :bar do
230
- executor do |args, options|
231
- if options[:bold]
232
- puts "BOLD!!!"
233
- else
234
- puts "plain"
235
- end
236
- end
237
-
238
- summary "Displays when this is a subcommand"
239
- para "Just prints 'bar'"
240
- para "A truly unremarkable command"
241
-
242
- header 'Option:'
243
- boolean :bold, "Bolds something" do
244
- negate 'un'
245
- end
246
-
247
- # Because there is no bar.arguments call,
248
- # it is now an error if there are extra
249
- # command line arguments to this command.
250
- end
251
-
252
- if __FILE__ == $0
253
- args = ['--un-bold']
254
-
255
- result = $bar_cmd.parse!(args)
256
-
257
- require 'pp'
258
- pp result.options[:bold] # => false
259
- pp result.args # => []
260
-
261
- $bar_cmd.execute!(args) # => 'plain'
262
-
263
- args << 'should-throw-error'
264
- $bar_cmd.execute!(args)
265
- end
266
-
267
- We can now create our super command.
268
-
269
- #!/usr/bin/env ruby
270
-
271
- # superfoo.rb
272
- require 'choosy'
273
- require 'foo'
274
- require 'bar'
275
-
276
- SUPERFOO_VERSION = "1.0.1"
277
-
278
- superfoo = Choosy::SuperCommand.new :superfoo do
279
- summary "This is a superfoo command"
280
- para "Say something, dammit!"
281
-
282
- # You can also add commands after instantiation.
283
- # Note that, when added, these commands have their
284
- # -h/--help/--version flags suppressed, so you'll
285
- # need to add those flags here.
286
- command $bar_cmd
287
- command $foo_cmd
288
-
289
- # Creates a 'help' command, message optional
290
- help "Prints this help message"
291
-
292
- # Create some global options that are parsed
293
- # defore result options
294
-
295
- # Here, check that a YAML file exists, and attempt
296
- # to load it's parsed contents into this option.
297
- # There is also a 'file' type that checks to see
298
- # if the file exists. With both 'file' and 'yaml',
299
- # if the file is missing, the option fails with an
300
- # error.
301
- yaml :Config, "Configure your superfoo with a YAML configuration file." do
302
- default File.join(ENV['HOME'], '.superfoo.yml')
303
- end
304
-
305
- # Adds a global --version flag.
306
- version "#{SUPERFOO_VERSION}"
307
- end
308
-
309
- if __FILE__ == $0
310
- args = ['foo',
311
- '-c', '5',
312
- '--config', 'superfoo.yaml',
313
- '--prefix', '{',
314
- '--suffix', '}',
315
- 'cruft',
316
- 'bar',
317
- '--bold']
318
-
319
- result = superfoo.parse!(args)
320
-
321
- require 'pp'
322
- pp result[:Config] # => {:here => 'text'} # Pulled the config!
323
-
324
- foores = result.subresults[0]
325
-
326
- pp foores[:Config] # => {:here => 'text'} # Passed along!
327
- pp foores[:prefix] # => '{'
328
- pp foores[:suffix] # => '}'
329
- pp foores[:count] # => 5
330
- pp foores[:bold] # => true
331
- pp foores.options # => {:prefix => '{', :suffix => '}'
332
- # :count => 5,
333
- # :bold => true,
334
- # :words => [],
335
- # :config => '~/.superfoo' }
336
- pp foores.args # => ['cruft', 'bar']
337
-
338
- # Now, we can call the result
339
- superfoo.execute!(args) ## Calls superfoo.result.execute!
340
- ## Prints:
341
- # BOLDED!!
342
- # {foo}
343
- # {foo,foo}
344
- # {foo,foo,foo}
345
- # {foo,foo,foo,foo}
346
- # {foo,foo,foo,foo,foo}
347
- # and cruft bar
348
-
349
- # Instead of parsing the 'bar' parameter as an argument to
350
- # the foo command, so that when the first argument that matches
351
- # another command name is encountered, it stops parsing the
352
- # current command and passes the rest of the arguments to the
353
- # next command.
354
- #
355
- # In this case, we call the 'alter' method to use the DSL
356
- # syntax again to alter this command.
357
- #
358
- # You can also set this inside a SuperChoosy.new {...}
359
- # block.
360
- superfoo.alter do
361
- parsimonious
362
- end
363
-
364
- result = superfoo.parse!(args)
365
-
366
- foores = result.subresults[0]
367
- pp foores[:Config] # => {:here => 'text'} # Passed along!
368
- pp foores.command.name # => :foo
369
- pp foores[:prefix] # => '{'
370
- pp foores[:suffix] # => '}'
371
- pp foores[:count] # => 5
372
- pp foores[:bold] # => true
373
- pp foores.options # => {:prefix => '{', :suffix => '}'
374
- # :count => 5,
375
- # :bold => false,
376
- # :words => [],
377
- # :config => {:here => 'text'}
378
- # }
379
- pp foores.args # => ['cruft']
380
-
381
- barres = result.subresults[1]
382
- pp barres.command.name # => :bar
383
- pp barres[:bold] # => true
384
- pp barres.options # => {:bold => true,
385
- # :config => {:here => 'text'}
386
- # }
387
- pp barres.args # => []
388
-
389
- # Now, execute the results in order
390
- superfoo.execute!(args) ## Same as:
391
- # results.each do |subcommand|
392
- # command.execute!
393
- # end
394
- ## Prints:
395
- # {foo}
396
- # {foo}
397
- # and cruft
398
- # BOLDED BAR
399
- end
400
-
401
-
402
- # Output Printing
403
-
404
- Choosy allows you to customize the output printing of your documentation. It exposes the internal object model to any class that implements a <code>print!(command)</code> method.
405
-
406
- The <code>:standard</code> printer that is the default for any command can also be customized to meet some of your needs:
407
-
408
- Choosy::Command.new :foo do
409
- printer :standard, # The default printer
410
- :max_width => 80, # Defaults to the column witdh of the terminal
411
- :color => true, # Default is true
412
- :header_styles => [:bold, :green], # Defaults to [:bold, :blue]
413
- :indent => ' ', # Defaults to this width
414
- :offset => ' ' # Defaults to this width
415
-
416
- help "Show this help command."
417
- end
418
-
419
- This above example sets some useful properties for the printer. First, the <code>:max_width</code> limits the wrapping size on the console. By default, choosy tries to be smart and wrap to the currend column width, but you can introduce this hash parameter as a default max. Next, you can turn off and on color printing by setting <code>:color</code>. Color is on by default, so it's actually superfluous in this example -- just a demonstration of the syntax. The <code>:header_styles</code> is an array of styles that will be applied to the headers for this document. By default, headers are <code>[:bold, :blue]</code>. Most of the ANSI colors and codes are supported, but check <code>lib/choosy/printing/color.rb</code> for additional options. The last two options given are actually formatting spacers in the output that you can customize: <code>:indent</code> is the default indent for commands and options; <code>:offset</code> is the distance between the options and commands to their associated descriptive text.
420
-
421
- For those who want the nice, manpage experience, there's also the <code>:manpage</code> printer:
422
-
423
- Choosy::Command.new :foo do
424
- printer :manpage,
425
- :max_width => 80, # Same as :standard
426
- :color => true, # Same as :standard
427
- :header_styles => [:bold, :green], # Same as :standard
428
- :option_sytles => [:bold], # Same as :standard
429
- :indent => ' ', # Same as :standard
430
- :offset => ' ', # Same as :standard
431
- :version => FOO_VERSION, # Will use the version name you specify, see below.
432
- :section => 1, # Default is always '1'
433
- :date => '03/24/2011', # Date you want displayed
434
- :manual => 'Foo Co.' # The manual page group
435
-
436
- version FOO_VERSION # If you don't supply a version above, this will be used
437
- end
438
-
439
- Because the library is super-awesome, the manpage will even be in color when piped to <code>less -R</code> (the default)! If you don't like the format of my manpage, feel free to implement your own using the <code>choosy/printing/manpage</code> class, a useful utility class for formatting manpage output correctly.
440
-
441
- If you already have some templates that you'd like to use, there is also the <code>:erb</code> template that can be customized by writing a template of your choice:
442
-
443
- Choosy::Command.new :foo do
444
- printer :erb,
445
- :color => true, # Defaults to true
446
- :template => 'path/to/file.erb' # Required
447
- end
448
-
449
- The ERB printer also accepts the <code>:color</code> option. The color is exposed via a <code>color</code> property in the template; the command is exposed by the <code>command</code> property.
450
-
451
- Finally, because I don't want to tell you how to print your help, I also give you the option of supplying your own printer. Just create a class with a <code>print!(command)</code> method on that class, and it will be passed in the command that it should print the help for. I have supplied some code you may find useful in <code>choosy/terminal</code> that will help with things like finding commands and determining the column width of the terminal.
452
-
453
- class CustomPrinter
454
- def print!(command)
455
- puts "I got called on help for #{command.name}"
456
- end
457
- end
458
-
459
- Choosy::Command.new :foo do
460
- printer CustomPrinter.new
461
- end
462
-
463
-