choosy 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/README.markdown +229 -221
  2. data/Rakefile +21 -3
  3. data/examples/bar.rb +44 -0
  4. data/examples/foo.rb +198 -0
  5. data/examples/superfoo.rb +125 -0
  6. data/lib/VERSION +1 -1
  7. data/lib/choosy/argument.rb +51 -0
  8. data/lib/choosy/base_command.rb +22 -7
  9. data/lib/choosy/command.rb +12 -4
  10. data/lib/choosy/dsl/argument_builder.rb +88 -0
  11. data/lib/choosy/dsl/base_command_builder.rb +71 -56
  12. data/lib/choosy/dsl/command_builder.rb +14 -2
  13. data/lib/choosy/dsl/option_builder.rb +43 -83
  14. data/lib/choosy/dsl/super_command_builder.rb +37 -9
  15. data/lib/choosy/option.rb +13 -11
  16. data/lib/choosy/parse_result.rb +8 -27
  17. data/lib/choosy/parser.rb +20 -16
  18. data/lib/choosy/printing/color.rb +39 -21
  19. data/lib/choosy/printing/erb_printer.rb +12 -3
  20. data/lib/choosy/printing/formatting_element.rb +17 -0
  21. data/lib/choosy/printing/help_printer.rb +204 -117
  22. data/lib/choosy/printing/terminal.rb +53 -0
  23. data/lib/choosy/super_command.rb +6 -6
  24. data/lib/choosy/super_parser.rb +26 -15
  25. data/lib/choosy/verifier.rb +61 -6
  26. data/spec/choosy/base_command_spec.rb +27 -2
  27. data/spec/choosy/command_spec.rb +31 -9
  28. data/spec/choosy/dsl/argument_builder_spec.rb +180 -0
  29. data/spec/choosy/dsl/base_command_builder_spec.rb +87 -44
  30. data/spec/choosy/dsl/commmand_builder_spec.rb +15 -4
  31. data/spec/choosy/dsl/option_builder_spec.rb +101 -191
  32. data/spec/choosy/dsl/super_command_builder_spec.rb +34 -9
  33. data/spec/choosy/parser_spec.rb +30 -8
  34. data/spec/choosy/printing/color_spec.rb +19 -5
  35. data/spec/choosy/printing/help_printer_spec.rb +152 -73
  36. data/spec/choosy/printing/terminal_spec.rb +27 -0
  37. data/spec/choosy/super_command_spec.rb +17 -17
  38. data/spec/choosy/super_parser_spec.rb +20 -10
  39. data/spec/choosy/verifier_spec.rb +137 -47
  40. data/spec/integration/command-A_spec.rb +6 -6
  41. data/spec/integration/command-B_spec.rb +45 -0
  42. data/spec/integration/supercommand-A_spec.rb +33 -27
  43. data/spec/integration/supercommand-B_spec.rb +32 -0
  44. data/spec/spec_helpers.rb +8 -5
  45. metadata +95 -54
@@ -19,154 +19,163 @@ This library should never:
19
19
 
20
20
  # Examples
21
21
 
22
- #!/usr/bin/env ruby
22
+ #!/usr/bin/env ruby -w
23
23
  # foo.rb
24
-
25
- require 'rubygems'
24
+
25
+ $LOAD_PATH.unshift File.join(File.dirname(File.dirname(__FILE__)), 'lib')
26
26
  require 'choosy'
27
-
28
- FOO_VERSION = 1.0.1
29
-
27
+
28
+ FOO_VERSION = '1.0.1'
29
+
30
30
  class FooExecutor
31
- def execute!(options, args)
31
+ def execute!(args, options)
32
32
  puts "BOLDED!!" if options[:bold]
33
33
  options[:count].times do
34
- puts "#{options[:prefix]}#{options[:words].push('foo').join(',')#{options[:suffix}}"
34
+ puts "#{options[:prefix]}#{options[:words].push('foo').join(',')}#{options[:suffix]}"
35
35
  end
36
36
  puts "and #{args.join ' '}"
37
37
  end
38
38
  end
39
-
39
+
40
40
  foo_cmd = Choosy::Command.new :foo do |foo|
41
41
  # Add a class to do the execution when you call foo_cmd.execute!
42
42
  # You can also use a proc that takes the options and the args, like:
43
- # foo.executor { |opts, args| puts 'Hi!' }
44
- foo.executor FooExecutor.new
45
-
43
+ # executor { |args, options| puts 'Hi!' }
44
+ executor FooExecutor.new
45
+
46
+ # When used as a subcommand, you need a summary for the help screen
47
+ summary "This is a nice command named 'foo'"
48
+
46
49
  # You can add your custom printer by giving the
47
50
  # full path to an ERB template file here.
48
51
  # The default printer is :standard, but you can
49
- # also use the builtin printer :compact. The
52
+ # also use the builtin printer :erb, with the :tempates
53
+ # parameter to set the erb template you wish to use. The
50
54
  # output can be colored or uncolored, though the
51
55
  # default is colored.
52
- foo.printer :standard, :colored => true
53
-
54
- foo.summary 'Prints out "foo" to the console"
55
- foo.desc <<HERE
56
- This is a long description about what 'foo' is
57
- and how it works. Don't worry your pretty little head
58
- about the details.
59
- HERE
60
-
61
- foo.separator 'Required Options:'
62
-
56
+ printer :standard, :color => true, :header_styles => [:bold, :green]
57
+
58
+ para 'Prints out "foo" to the console'
59
+ 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).'
60
+
61
+ header 'Required Options:' # Formatted according to the header_styles for the printer
62
+
63
63
  # A shorthand for a common option type.
64
64
  # It adds the '-p/--prefix PREFIX' infomation for you.
65
- foo.single :prefix, "A prefix for 'foo'" do |p|
66
- p.default '<'
67
- p.required
65
+ single :prefix, "A prefix for 'foo'" do
66
+ default '<'
67
+ required
68
68
  end
69
-
69
+
70
70
  # The long way to do the same thing as above, except with
71
71
  # explicitly named dependencies
72
- foo.option :suffix => [:prefix] do |o|
73
- o.short '-s'
74
- o.long '--suffix', 'SUFFIX'
75
- o.desc 'A suffix for "foo"'
76
- o.required
77
-
78
- o.validate do |suffix|
79
- if suffix == foo[:prefix]
80
- o.fail "You can't matching prefixes and suffixes, you heathen!"
72
+ option :suffix => [:prefix] do
73
+ short '-s'
74
+ long '--suffix', 'SUFFIX'
75
+ desc 'A suffix for "foo"'
76
+ required
77
+
78
+ validate do |suffix, options|
79
+ if suffix == options[:prefix]
80
+ die "You can't matching prefixes and suffixes, you heathen!"
81
81
  end
82
82
  end
83
83
  end
84
-
84
+
85
85
  # Just like the 'single' method above, except now it automatically
86
86
  # requires/casts the argument to this flag into an integer. These commands
87
87
  # also take an optional hash as the last argument, which can be used instead
88
88
  # of a block.
89
- foo.integer :count, 'The number of times to repeat "foo"', :required => true
90
-
91
- foo.separator
92
- foo.separator 'Options:'
93
-
94
- foo.option :words do |o|
95
- o.short '-w'
96
- o.long '--words', 'WORDS+' # By default, the '+' at the end
89
+ integer :count, 'The number of times to repeat "foo"', :required => true
90
+
91
+ header 'Options:', :bold, :blue # Format this header differently, overrides 'header_styles'
92
+
93
+ option :words do
94
+ short '-w'
95
+ long '--words', 'WORDS+' # By default, the '+' at the end
97
96
  # means that this takes multiple
98
97
  # arguments. You put a '-' at
99
98
  # the end of the argument list
100
99
  # to stop parsing this option
101
100
  # and allow for regular args.
102
- o.desc "Other fun words to put in quotes"
103
- o.default [] # The default anyway on multple arg options
101
+ desc "Other fun words to put in quotes"
104
102
 
105
103
  # Sets the exact count of the number of arguments it accepts.
106
104
  # also allowable are the single selectors :zero and :one.
107
105
  # By default, the option 'WORDS+' sets the range to be
108
106
  # {:at_least => 1, :at_most => 1000 }
109
- o.count {:at_least => 2, :at_most => 10 }
110
-
111
- o.validate do |words|
107
+ count :at_least => 2, :at_most => 10
108
+
109
+ validate do |words, options|
112
110
  words.each do |word|
113
111
  if word !~ /\w+/
114
- o.fail "I can't print that: #{word}"
112
+ die "I can't print that: #{word}"
115
113
  end
116
114
  end
117
115
  end
118
116
  end
119
-
117
+
120
118
  # Alternatively, we could have done the following:
121
- foo.strings :words, "Other fun words to put in quotes" do |w|
122
- w.count {:at_least => 2, :at_most => 10 }
123
- w.validate do |words|
119
+ strings :words, "Other fun words to put in quotes" do
120
+ count 2..10
121
+ default []
122
+ validate do |words, options|
124
123
  words.each do |word|
125
124
  if word !~ /\w+/
126
- w.fail "I can't print that: #{word}"
125
+ die "I can't print that: #{word}"
127
126
  end
128
127
  end
129
128
  end
130
129
  end
131
-
130
+
132
131
  # Yet another shorthand notation for options, since they
133
- # are boolean by default
134
- foo.option :bold => {:long => '--bold', :default => false}
135
-
136
- options.separator
132
+ # are boolean by default. Here, we add a negation to the
133
+ # long flag of the option, creating [-b|--bold|--un-bold] flags.
134
+ # By default, calling 'negate' in a block without an argument
135
+ # uses the '--no-' prefix instead.
136
+ boolean :bold, "Bold this option", :default => false, :negate => 'un'
137
+
137
138
  # Tail options
138
-
139
+
139
140
  # When any of the simpler notations are suffixed with a '_'
140
141
  # character, the short option is always suppressed.
141
- foo.boolean_ :debug, "Prints out extra debugging output."
142
-
142
+ boolean_ :debug, "Prints out extra debugging output."
143
+
143
144
  # The '_' characters are replaced with '-' in flags, so the
144
- # following creates a '--no-color' flag.
145
- foo.boolean_ :no_color, "Turns off coloring in the output" do |o|
146
- o.validate do
147
- foo.printer :standard, :colored => false
145
+ # following creates a '--[no-]color' flag.
146
+ boolean_ :color, "Turns on/off coloring in the output. Defalt is on." do
147
+ negate
148
+ default true
149
+ validate do
150
+ foo.command.alter do
151
+ printer :standard, :colored => false
152
+ end
148
153
  end
149
154
  end
150
-
155
+
151
156
  # Adds the standard -h/--help option.
152
157
  # Should skip the '-h' flag if already set.
153
- foo.help
154
-
158
+ help # Automatically adds the description if not passed an argument. You can supply your own
159
+
155
160
  # Adds the --version option.
156
- foo.version "Foo: #{FOO_VERSION}"
157
-
161
+ version "Foo: #{FOO_VERSION}"
162
+
158
163
  # Now, add some validation for any addtional arguments
159
- # that are left over after the parsing.
160
- foo.arguments do |args|
161
- if args.empty?
162
- a.fail "You have to pass in empty arguments that do nothing!"
163
- end
164
- if args.count >= 3
165
- a.fail "Whoa there! You're going argument crazy!"
164
+ # that are left over after the parsing the options.
165
+ arguments do
166
+ metaname 'ARGS'
167
+ count 1..10
168
+ validate do |args, options|
169
+ if args.empty?
170
+ die "You have to pass in empty arguments that do nothing!"
171
+ end
172
+ if args.count == 10
173
+ die "Whoa there! You're going argument crazy!"
174
+ end
166
175
  end
167
176
  end
168
177
  end
169
-
178
+
170
179
  if __FILE__ == $0
171
180
  # Parses and validates the options.
172
181
  args = ['--prefix', '{',
@@ -175,7 +184,7 @@ This library should never:
175
184
  # The '-' stops parsing this option, so that:
176
185
  'handsom', 'devil',
177
186
  'http://not.posting.here', # will be regular arguments
178
- '-c, '3', # Count
187
+ '-c', '3', # Count
179
188
  '--', # Stops parsing all arguments
180
189
  '-h', '--help', '-v', '--version' # Ignored
181
190
  ]
@@ -184,16 +193,17 @@ This library should never:
184
193
  require 'pp'
185
194
  pp result[:prefix] # => '{'
186
195
  pp result[:suffix] # => '}'
187
- pp reuslt[:count] # => 3
196
+ pp result[:count] # => 3
188
197
  pp result[:bold] # => false
189
- pp reuslt[:words] # => ['high', 'there', 'you']
190
- pp reuslt.args # => ['handsom', 'devil',
198
+ pp result[:words] # => ['high', 'there', 'you']
199
+ pp result.args # => ['handsom', 'devil',
191
200
  # 'http://not.posting.here',
192
201
  # '-h', '--help', '-v', '--version']
193
202
  pp result.options # => {:prefix => '{', :suffix => '}'
194
203
  # :count => 3, :bold => false,
195
- # :words => ['high', 'there', 'you']}
196
-
204
+ # :words => ['high', 'there', 'you'],
205
+ # :debug => false, :color => true}
206
+
197
207
  # Now, call the command that does the actual work.
198
208
  # This passes the foo_cmd.options and the foo_cmd.args
199
209
  # as arguments to the executors 'execute!' method.
@@ -205,7 +215,7 @@ This library should never:
205
215
  # {high,there,you,foo}
206
216
  # {high,there,you,foo}
207
217
  # and handsom devil http://not.posting.here -h --help -v --verbose
208
-
218
+
209
219
  end
210
220
 
211
221
  ### Super Commands
@@ -214,180 +224,178 @@ You can also combine multiple choices into an uber-choice, creating
214
224
  commands that look a lot like git or subversion.
215
225
 
216
226
  First, we create another command.
217
-
218
- #!/usr/bin/env ruby
219
- # bar.rb
220
227
 
221
- require 'rubygems'
228
+ #!/usr/bin/env ruby -w
229
+ # bar.rb
230
+
231
+ $LOAD_PATH.unshift File.join(File.dirname(File.dirname(__FILE__)), 'lib')
222
232
  require 'choosy'
223
-
224
- class BarExecutor
225
- def execute!(options, args)
233
+
234
+ # Create a new command
235
+ bar_cmd = Choosy::Command.new :bar do
236
+ executor do |args, options|
226
237
  if options[:bold]
227
- puts "BOLDED BAR"
238
+ puts "BOLD!!!"
228
239
  else
229
- puts "bar"
240
+ puts "plain"
230
241
  end
231
242
  end
232
- end
233
243
 
234
- # Create a new command
235
- bar_cmd = Choosy::Command.new :bar do |bar|
236
- bar.executor BarExecutor.new
237
- bar.summary "Just prints 'bar'"
238
- bar.desc "A truly unremarkable command"
239
-
240
- bar.boolean :bold, "Bolds something"
241
-
244
+ summary "Displays when this is a subcommand"
245
+ para "Just prints 'bar'"
246
+ para "A truly unremarkable command"
247
+
248
+ header 'Option:'
249
+ boolean :bold, "Bolds something" do
250
+ negate 'un'
251
+ end
252
+
242
253
  # Because there is no bar.arguments call,
243
254
  # it is now an error if there are extra
244
255
  # command line arguments to this command.
245
256
  end
246
257
 
258
+ if __FILE__ == $0
259
+ args = ['--un-bold']
260
+
261
+ result = bar_cmd.parse!(args)
262
+
263
+ require 'pp'
264
+ pp result.options[:bold] # => false
265
+ pp result.args # => []
266
+
267
+ bar_cmd.execute!(args) # => 'plain'
268
+
269
+ args << 'should-throw-error'
270
+ bar_cmd.execute!(args)
271
+ end
272
+
247
273
  We can now create our super command.
248
274
 
249
- #!/usr/bin/env ruby
275
+ #!/usr/bin/env ruby -w
250
276
  # superfoo.rb
251
-
252
- require 'rubygems'
277
+
278
+ $LOAD_PATH.unshift File.join(File.dirname(File.dirname(__FILE__)), 'lib')
279
+ $LOAD_PATH.unshift File.join(File.dirname(File.dirname(__FILE__)), 'examples')
253
280
  require 'choosy'
254
- require 'foo.rb'
255
- require 'bar.rb'
281
+ require "foo"
282
+ require "bar"
256
283
 
257
284
  SUPERFOO_VERSION = "1.0.1"
258
285
 
259
- superfoo = Choosy::SuperCommand.new :superfoo do |superfoo|
260
- superfoo.summary "This is a superfoo command."
261
- superfoo.desc "Say something, dammit!"
262
-
286
+ superfoo = Choosy::SuperCommand.new :superfoo do
287
+ summary "This is a superfoo command"
288
+ para "Say something, dammit!"
289
+
263
290
  # You can also add commands after instantiation.
264
291
  # Note that, when added, these commands have their
265
292
  # -h/--help/--version flags suppressed, so you'll
266
293
  # need to add those flags here.
267
- superfoo.commands bar_cmd
268
-
269
- # Creates a 'help' command
270
- superfoo.help do |help|
271
- help.summary "Prints this help message"
272
- end
273
-
274
- # Create some global options that are parsed
275
- # defore subcommand options
294
+ command bar_cmd
295
+ command foo_cmd
276
296
 
277
- superfoo.option :config do |o|
278
- o.long '--config', 'FILE'
279
- o.desc "Configure your superfoo with a configuration file."
297
+ # Creates a 'help' command, message optional
298
+ help "Prints this help message"
280
299
 
281
- o.validate do |config|
282
- if !File.exist? config
283
- o.fail "Unable to find configuration file!"
284
- end
285
- end
300
+ # Create some global options that are parsed
301
+ # defore result options
302
+
303
+ # Here, check that a YAML file exists, and attempt
304
+ # to load it's parsed contents into this option.
305
+ # There is also a 'file' type that checks to see
306
+ # if the file exists. With both 'file' and 'yaml',
307
+ # if the file is missing, the option fails with an
308
+ # error.
309
+ yaml :Config, "Configure your superfoo with a YAML configuration file." do
310
+ default File.join(ENV['HOME'], '.superfoo.yml')
286
311
  end
287
312
 
288
313
  # Adds a global --version flag.
289
- superfoo.version do
290
- puts "#{SUPERFOO_VERSION}"
291
- end
314
+ version "#{SUPERFOO_VERSION}"
292
315
  end
293
316
 
294
- # Add a command after the fact.
295
- superfoo.commands foo_cmd
296
-
297
317
  if __FILE__ == $0
298
- superfoo.parse! ['-c', '5',
299
- 'foo',
300
- '--config', '~/.superfoo',
301
- '--prefix', '{',
302
- '--suffix', '}',
303
- 'cruft',
304
- 'bar',
305
- '--bold']
306
-
318
+ args = ['foo',
319
+ '-c', '5',
320
+ '--config', '~/.superfoo',
321
+ '--prefix', '{',
322
+ '--suffix', '}',
323
+ 'cruft',
324
+ 'bar',
325
+ '--bold']
326
+
327
+ result = superfoo.parse!(args)
328
+
307
329
  require 'pp'
308
- pp superfoo[:config] # => '~/.superfoo'
309
- pp superfoo.subcommand.name # => :foo
310
- pp superfoo.subcommand[:prefix] # => '{'
311
- pp superfoo.subcommand[:suffix] # => '}'
312
- pp superfoo.subcommand[:count] # => 2
313
- pp superfoo.subcommand[:bold] # => true
314
- pp superfoo.subcommand.options # => {:prefix => '{', :suffix => '}'
315
- # :count => 2,
316
- # :bold => true,
317
- # :words => [],
318
- # :config => '~/.superfoo' }
319
- pp superfoo.subcommand.args # => ['cruft', 'bar']
330
+ pp result[:config] # => '~/.superfoo'
331
+ pp result.name # => :foo
332
+ pp result[:prefix] # => '{'
333
+ pp result[:suffix] # => '}'
334
+ pp result[:count] # => 2
335
+ pp result[:bold] # => true
336
+ pp result.options # => {:prefix => '{', :suffix => '}'
337
+ # :count => 2,
338
+ # :bold => true,
339
+ # :words => [],
340
+ # :config => '~/.superfoo' }
341
+ pp result.args # => ['cruft', 'bar']
342
+
343
+ # Now, we can call the result
344
+ superfoo.execute!(args) ## Calls superfoo.result.execute!
345
+ ## Prints:
346
+ # BOLDED!!
347
+ # {foo}
348
+ # {foo}
349
+ # and cruft bar
320
350
 
321
- pp superfoo.options # => {:prefix => '{', :suffix => '}'
322
- # :count => 2,
323
- # :bold => true,
324
- # :words => [],
325
- # :config => '~/.superfoo' }
326
- pp superfoo.args # => ['cruft', 'bar']
327
-
328
- # Now, we can call the subcommand
329
- superfoo.execute! ## Calls superfoo.subcommand.execute!
330
- ## Prints:
331
- # BOLDED!!
332
- # {foo}
333
- # {foo}
334
- # and cruft bar
335
-
336
- # We got what we wanted, so reset the parser.
337
- superfoo.reset!
338
-
339
351
  # Instead of parsing the 'bar' parameter as an argument to
340
352
  # the foo command, so that when the first argument that matches
341
353
  # another command name is encountered, it stops parsing the
342
354
  # current command and passes the rest of the arguments to the
343
355
  # next command.
344
356
  #
345
- # You can also set this inside a SuperChoosy.new {|s| ... }
357
+ # In this case, we call the 'alter' method to use the DSL
358
+ # syntax again to alter this command.
359
+ #
360
+ # You can also set this inside a SuperChoosy.new {...}
346
361
  # block.
347
- superfoo.parsimonious
348
-
349
- superfoo.parse! ['-c', '5',
350
- 'foo',
351
- '--config', '~/.superfoo',
352
- '--prefix', '{',
353
- '--suffix', '}',
354
- 'cruft',
355
- 'bar',
356
- '--bold']
362
+ superfoo.alter do
363
+ parsimonious
364
+ end
365
+
366
+ result = superfoo.parse!(args)
357
367
 
358
- pp superfoo[:config] # => '~/.superfoo'
359
- pp superfoo.subcommand.name # => :foo
360
- pp superfoo.subcommands[0].name # => :foo
361
- pp superfoo.subcommands[0][:prefix] # => '{'
362
- pp superfoo.subcommands[0][:suffix] # => '}'
363
- pp superfoo.subcommands[0][:count] # => 2
364
- pp superfoo.subcommands[0][:bold] # => true
365
- pp superfoo.subcommands[0].options # => {:prefix => '{', :suffix => '}'
366
- # :count => 2,
367
- # :bold => false,
368
- # :words => [],
369
- # :config => '~/.superfoo' }
370
- pp superfoo.subcommands[0].args # => ['cruft']
371
-
372
- pp superfoo.subcommands[1].name # => :bar
373
- pp superfoo.subcommands[1][:bold] # => true
374
- pp superfoo.subcommands[1].options # => {:bold => true,
375
- # :config => '~/.superfoo'}
376
- pp superfoo.subcommands[1].args # => []
368
+ pp result.name # => :superfoo
369
+ pp result[:config] # => '~/.superfoo'
370
+ pp result.subresults[0].name # => :foo
371
+ pp result.subresults[0][:prefix] # => '{'
372
+ pp result.subresults[0][:suffix] # => '}'
373
+ pp result.subresults[0][:count] # => 2
374
+ pp result.subresults[0][:bold] # => true
375
+ pp result.subresults[0].options # => {:prefix => '{', :suffix => '}'
376
+ # :count => 2,
377
+ # :bold => false,
378
+ # :words => [],
379
+ # :config => '~/.superfoo' }
380
+ pp result.subresults[0].args # => ['cruft']
381
+
382
+ pp result.subresults[1].name # => :bar
383
+ pp result.subresults[1][:bold] # => true
384
+ pp result.subresults[1].options # => {:bold => true,
385
+ # :config => '~/.superfoo'}
386
+ pp result.subresults[1].args # => []
377
387
 
378
- pp superfoo.options # => {:config => '~/.superfoo'}
379
- pp superfoo.args # => []
380
-
381
- # Now, execute the subcommands in order
382
- superfoo.execute! ## Same as:
383
- # superfoo.subcommands.each do |subcommand|
384
- # command.execute!
385
- # end
386
- ## Prints:
387
- # {foo}
388
- # {foo}
389
- # and cruft
390
- # BOLDED BAR
388
+ # Now, execute the results in order
389
+ superfoo.execute!(args) ## Same as:
390
+ # results.each do |subcommand|
391
+ # command.execute!
392
+ # end
393
+ ## Prints:
394
+ # {foo}
395
+ # {foo}
396
+ # and cruft
397
+ # BOLDED BAR
391
398
  end
399
+
392
400
 
393
401
  ### TODO: Output Printing